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));
154 sampass = pdb_getsampwnam(mach_acct);
157 if ((sampass) != NULL && !(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) &&
158 ((pass=pdb_get_nt_passwd(sampass)) != NULL))
160 memcpy(md4pw, pass, 16);
161 dump_data(5, md4pw, 16);
166 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
170 /*************************************************************************
172 *************************************************************************/
174 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
176 uint32 status = NT_STATUS_NOPROBLEMO;
180 if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
183 fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
184 q_u->uni_logon_clnt.uni_str_len));
187 fstrcat(mach_acct, "$");
189 if (get_md4pw((char *)vuser->dc.md4pw, mach_acct)) {
190 /* copy the client credentials */
191 memcpy(vuser->dc.clnt_chal.data , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
192 memcpy(vuser->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
194 /* create a server challenge for the client */
195 /* Set these to random values. */
196 generate_random_buffer(vuser->dc.srv_chal.data, 8, False);
198 memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8);
200 memset((char *)vuser->dc.sess_key, '\0', sizeof(vuser->dc.sess_key));
202 /* from client / server challenges and md4 password, generate sess key */
203 cred_session_key(&vuser->dc.clnt_chal, &vuser->dc.srv_chal,
204 (char *)vuser->dc.md4pw, vuser->dc.sess_key);
206 /* lkclXXXX take a guess at a good error message to return :-) */
207 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
210 /* set up the LSA REQUEST CHALLENGE response */
211 init_net_r_req_chal(r_u, &vuser->dc.srv_chal, status);
216 /*************************************************************************
218 *************************************************************************/
220 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
222 uint32 status = NT_STATUS_NOPROBLEMO;
228 if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
229 return NT_STATUS_NO_SUCH_USER;
233 /* check that the client credentials are valid */
234 if (cred_assert(&q_u->clnt_chal, vuser->dc.sess_key, &vuser->dc.clnt_cred.challenge, srv_time)) {
236 /* create server challenge for inclusion in the reply */
237 cred_create(vuser->dc.sess_key, &vuser->dc.srv_cred.challenge, srv_time, &srv_cred);
239 /* copy the received client credentials for use next time */
240 memcpy(vuser->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
241 memcpy(vuser->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
243 status = NT_STATUS_ACCESS_DENIED;
246 srv_flgs.neg_flags = 0x000001ff;
248 /* set up the LSA AUTH 2 response */
249 init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
254 /*************************************************************************
256 *************************************************************************/
258 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
260 uint16 vuid = p->vuid;
261 uint32 status = NT_STATUS_WRONG_PASSWORD;
264 SAM_ACCOUNT *sampass;
267 unsigned char pwd[16];
270 if ((vuser = get_valid_user_struct(vuid)) == NULL)
271 return NT_STATUS_NO_SUCH_USER;
273 /* checks and updates credentials. creates reply credentials */
274 if (!deal_with_creds(vuser->dc.sess_key, &vuser->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
275 return NT_STATUS_INVALID_HANDLE;
277 memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
279 DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
281 pstrcpy(mach_acct, dos_unistrn2(q_u->clnt_id.login.uni_acct_name.buffer,
282 q_u->clnt_id.login.uni_acct_name.uni_str_len));
284 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
287 sampass = pdb_getsampwnam(mach_acct);
291 return NT_STATUS_NO_SUCH_USER;
293 DEBUG(100,("Server password set : new given value was :\n"));
294 for(i = 0; i < 16; i++)
295 DEBUG(100,("%02X ", q_u->pwd[i]));
298 cred_hash3( pwd, q_u->pwd, vuser->dc.sess_key, 0);
300 /* lies! nt and lm passwords are _not_ the same: don't care */
301 pdb_set_lanman_passwd (sampass, pwd);
302 pdb_set_nt_passwd (sampass, pwd);
303 pdb_set_acct_ctrl (sampass, ACB_WSTRUST);
306 ret = pdb_update_sam_account (sampass,False);
310 status = NT_STATUS_NOPROBLEMO;
312 /* set up the LSA Server Password Set response */
313 init_net_r_srv_pwset(r_u, &srv_cred, status);
319 /*************************************************************************
321 *************************************************************************/
323 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
329 if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
330 return NT_STATUS_NO_SUCH_USER;
332 /* checks and updates credentials. creates reply credentials */
333 if (!deal_with_creds(vuser->dc.sess_key, &vuser->dc.clnt_cred,
334 &q_u->sam_id.client.cred, &srv_cred))
335 return NT_STATUS_INVALID_HANDLE;
337 memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
339 /* XXXX maybe we want to say 'no', reject the client's credentials */
340 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
341 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
343 r_u->status = NT_STATUS_NOPROBLEMO;
348 /*************************************************************************
349 net_login_interactive:
350 *************************************************************************/
352 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, user_struct *vuser)
358 unsigned char key[16];
361 memcpy(key, vuser->dc.sess_key, 8);
363 memcpy(lm_pwd, id1->lm_owf.data, 16);
364 memcpy(nt_pwd, id1->nt_owf.data, 16);
366 #ifdef DEBUG_PASSWORD
368 dump_data(100, (char *)key, 16);
370 DEBUG(100,("lm owf password:"));
371 dump_data(100, lm_pwd, 16);
373 DEBUG(100,("nt owf password:"));
374 dump_data(100, nt_pwd, 16);
377 SamOEMhash((uchar *)lm_pwd, key, False);
378 SamOEMhash((uchar *)nt_pwd, key, False);
380 #ifdef DEBUG_PASSWORD
381 DEBUG(100,("decrypt of lm owf password:"));
382 dump_data(100, lm_pwd, 16);
384 DEBUG(100,("decrypt of nt owf password:"));
385 dump_data(100, nt_pwd, 16);
388 if (memcmp(pdb_get_lanman_passwd(sampass), lm_pwd, 16) != 0 ||
389 memcmp(pdb_get_nt_passwd(sampass), nt_pwd, 16) != 0) {
390 status = NT_STATUS_WRONG_PASSWORD;
396 /*************************************************************************
398 *************************************************************************/
400 static uint32 net_login_network(NET_ID_INFO_2 *id2, SAM_ACCOUNT *sampass)
402 BYTE *nt_pwd, *lanman_pwd;
404 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
405 id2->hdr_lm_chal_resp.str_str_len,
406 id2->hdr_nt_chal_resp.str_str_len));
408 /* JRA. Check the NT password first if it exists - this is a higher quality
409 password, if it exists and it doesn't match - fail. */
411 nt_pwd = pdb_get_nt_passwd(sampass);
412 lanman_pwd = pdb_get_lanman_passwd(sampass);
414 if (id2->hdr_nt_chal_resp.str_str_len == 24 && nt_pwd) {
415 if(smb_password_check((char *)id2->nt_chal_resp.buffer,
416 nt_pwd, id2->lm_chal))
417 return NT_STATUS_NOPROBLEMO;
419 return NT_STATUS_WRONG_PASSWORD;
422 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
423 if that is to be done, first move this entire function into a
424 library routine that calls the two smb_password_check() functions.
425 if disabling LM hashes (which nt can do for security reasons) then
426 an attempt should be made to disable them everywhere (which nt does
427 not do, for various security-hole reasons).
430 if (id2->hdr_lm_chal_resp.str_str_len == 24 && lanman_pwd &&
431 smb_password_check((char *)id2->lm_chal_resp.buffer,
432 lanman_pwd, id2->lm_chal))
433 return NT_STATUS_NOPROBLEMO;
435 /* oops! neither password check succeeded */
437 return NT_STATUS_WRONG_PASSWORD;
440 /*************************************************************************
442 *************************************************************************/
444 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
446 uint32 status = NT_STATUS_NOPROBLEMO;
447 uint16 vuid = p->vuid;
448 NET_USER_INFO_3 *usr_info = NULL;
450 SAM_ACCOUNT *sampass = NULL;
452 UNISTR2 *uni_samlogon_user = NULL;
454 user_struct *vuser = NULL;
456 usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
458 return NT_STATUS_NO_MEMORY;
459 ZERO_STRUCTP(usr_info);
461 if ((vuser = get_valid_user_struct(vuid)) == NULL)
462 return NT_STATUS_NO_SUCH_USER;
464 /* checks and updates credentials. creates reply credentials */
465 if (!deal_with_creds(vuser->dc.sess_key, &vuser->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
466 return NT_STATUS_INVALID_HANDLE;
468 memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
470 /* find the username */
472 switch (q_u->sam_id.logon_level) {
473 case INTERACTIVE_LOGON_TYPE:
474 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
476 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
479 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
481 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
484 DEBUG(2,("SAM Logon: unsupported switch value\n"));
485 return NT_STATUS_INVALID_INFO_CLASS;
488 /* check username exists */
490 pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
492 DEBUG(3,("User:[%s]\n", nt_username));
495 * Convert to a UNIX username.
498 map_username(nt_username);
500 /* get the account information */
502 sampass = pdb_getsampwnam(nt_username);
506 return NT_STATUS_NO_SUCH_USER;
508 acct_ctrl = pdb_get_acct_ctrl(sampass);
510 if (acct_ctrl & ACB_DISABLED)
511 return NT_STATUS_ACCOUNT_DISABLED;
513 /* Validate password - if required. */
515 if (!(acct_ctrl & ACB_PWNOTREQ)) {
516 switch (q_u->sam_id.logon_level) {
517 case INTERACTIVE_LOGON_TYPE:
518 /* interactive login. */
519 status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, sampass, vuser);
522 /* network login. lm challenge and 24 byte responses */
523 status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
528 if (status != NT_STATUS_NOPROBLEMO)
531 /* lkclXXXX this is the point at which, if the login was
532 successful, that the SAM Local Security Authority should
533 record that the user is logged in to the domain.
537 DOM_GID *gids = NULL;
540 pstring my_workgroup;
541 pstring domain_groups;
543 /* set up pointer indicating user/password failed to be found */
544 usr_info->ptr_user_info = 0;
546 /* XXXX hack to get standard_sub_basic() to use sam logon username */
547 /* possibly a better way would be to do a become_user() call */
548 sam_logon_in_ssb = True;
549 pstrcpy(samlogon_user, nt_username);
551 pstrcpy(my_workgroup, lp_workgroup());
552 pstrcpy(my_name, global_myname);
556 * This is the point at which we get the group
557 * database - we should be getting the gid_t list
558 * from /etc/group and then turning the uids into
559 * rids and then into machine sids for this user.
563 get_domain_user_groups(domain_groups, nt_username);
566 * make_dom_gids allocates the gids array. JRA.
569 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
571 sam_logon_in_ssb = False;
573 init_net_user_info3(p->mem_ctx, usr_info, sampass,
575 0, /* bad_pw_count */
576 num_gids, /* uint32 num_groups */
577 gids , /* DOM_GID *gids */
578 0x20 , /* uint32 user_flgs (?) */
579 NULL, /* char sess_key[16] */
580 my_name , /* char *logon_srv */
581 my_workgroup, /* char *logon_dom */
582 &global_sam_sid, /* DOM_SID *dom_sid */
583 NULL); /* char *other_sids */
586 /* XXXX maybe we want to say 'no', reject the client's credentials */
587 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
588 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
590 /* store the user information, if there is any. */
591 r_u->user = usr_info;
592 if (status == NT_STATUS_NOPROBLEMO && usr_info != NULL && usr_info->ptr_user_info != 0)
593 r_u->switch_value = 3; /* indicates type of validation user info */
595 r_u->switch_value = 0; /* indicates no info */
597 r_u->status = status;
598 r_u->auth_resp = 1; /* authoritative response */