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 /***********************************************************************************
100 init_net_r_srv_pwset:
101 ***********************************************************************************/
103 static void init_net_r_srv_pwset(NET_R_SRV_PWSET
*r_s
,
104 DOM_CRED
*srv_cred
, int status
)
106 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__
));
108 memcpy(&r_s
->srv_cred
, srv_cred
, sizeof(r_s
->srv_cred
));
109 r_s
->status
= status
;
111 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__
));
114 /******************************************************************
115 gets a machine password entry. checks access rights of the host.
116 ******************************************************************/
118 static BOOL
get_md4pw(char *md4pw
, char *mach_acct
)
120 SAM_ACCOUNT
*sampass
= NULL
;
126 * Currently this code is redundent as we already have a filter
127 * by hostname list. What this code really needs to do is to
128 * get a hosts allowed/hosts denied list from the SAM database
129 * on a per user basis, and make the access decision there.
130 * I will leave this code here for now as a reminder to implement
131 * this at a later date. JRA.
134 if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
135 client_name(), client_addr()))
137 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct
));
142 if(!pdb_init_sam(&sampass
))
145 /* JRA. This is ok as it is only used for generating the challenge. */
147 ret
=pdb_getsampwnam(sampass
, mach_acct
);
151 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct
));
152 pdb_free_sam(sampass
);
156 if (!(pdb_get_acct_ctrl(sampass
) & ACB_DISABLED
) && ((pass
=pdb_get_nt_passwd(sampass
)) != NULL
)) {
157 memcpy(md4pw
, pass
, 16);
158 dump_data(5, md4pw
, 16);
159 pdb_free_sam(sampass
);
163 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct
));
164 pdb_free_sam(sampass
);
169 /*************************************************************************
171 *************************************************************************/
173 uint32
_net_req_chal(pipes_struct
*p
, NET_Q_REQ_CHAL
*q_u
, NET_R_REQ_CHAL
*r_u
)
175 uint32 status
= NT_STATUS_NOPROBLEMO
;
178 if (!get_valid_user_struct(p
->vuid
))
179 return NT_STATUS_NO_SUCH_USER
;
181 fstrcpy(mach_acct
, dos_unistrn2(q_u
->uni_logon_clnt
.buffer
,
182 q_u
->uni_logon_clnt
.uni_str_len
));
185 fstrcat(mach_acct
, "$");
187 if (get_md4pw((char *)p
->dc
.md4pw
, mach_acct
)) {
188 /* copy the client credentials */
189 memcpy(p
->dc
.clnt_chal
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
190 memcpy(p
->dc
.clnt_cred
.challenge
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
192 /* create a server challenge for the client */
193 /* Set these to random values. */
194 generate_random_buffer(p
->dc
.srv_chal
.data
, 8, False
);
196 memcpy(p
->dc
.srv_cred
.challenge
.data
, p
->dc
.srv_chal
.data
, 8);
198 memset((char *)p
->dc
.sess_key
, '\0', sizeof(p
->dc
.sess_key
));
200 /* from client / server challenges and md4 password, generate sess key */
201 cred_session_key(&p
->dc
.clnt_chal
, &p
->dc
.srv_chal
,
202 (char *)p
->dc
.md4pw
, p
->dc
.sess_key
);
204 /* Save the machine account name. */
205 fstrcpy(p
->dc
.mach_acct
, mach_acct
);
208 /* lkclXXXX take a guess at a good error message to return :-) */
209 status
= NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
212 /* set up the LSA REQUEST CHALLENGE response */
213 init_net_r_req_chal(r_u
, &p
->dc
.srv_chal
, status
);
218 /*************************************************************************
220 *************************************************************************/
222 static void init_net_r_auth(NET_R_AUTH
*r_a
, DOM_CHAL
*resp_cred
, int status
)
224 memcpy(r_a
->srv_chal
.data
, resp_cred
->data
, sizeof(resp_cred
->data
));
225 r_a
->status
= status
;
228 /*************************************************************************
230 *************************************************************************/
232 uint32
_net_auth(pipes_struct
*p
, NET_Q_AUTH
*q_u
, NET_R_AUTH
*r_u
)
234 uint32 status
= NT_STATUS_NOPROBLEMO
;
238 if (!get_valid_user_struct(p
->vuid
))
239 return NT_STATUS_NO_SUCH_USER
;
243 /* check that the client credentials are valid */
244 if (cred_assert(&q_u
->clnt_chal
, p
->dc
.sess_key
, &p
->dc
.clnt_cred
.challenge
, srv_time
)) {
246 /* create server challenge for inclusion in the reply */
247 cred_create(p
->dc
.sess_key
, &p
->dc
.srv_cred
.challenge
, srv_time
, &srv_cred
);
249 /* copy the received client credentials for use next time */
250 memcpy(p
->dc
.clnt_cred
.challenge
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
251 memcpy(p
->dc
.srv_cred
.challenge
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
253 status
= NT_STATUS_ACCESS_DENIED
;
256 /* set up the LSA AUTH 2 response */
257 init_net_r_auth(r_u
, &srv_cred
, status
);
262 /*************************************************************************
264 *************************************************************************/
266 static void init_net_r_auth_2(NET_R_AUTH_2
*r_a
,
267 DOM_CHAL
*resp_cred
, NEG_FLAGS
*flgs
, int status
)
269 memcpy(r_a
->srv_chal
.data
, resp_cred
->data
, sizeof(resp_cred
->data
));
270 memcpy(&r_a
->srv_flgs
, flgs
, sizeof(r_a
->srv_flgs
));
271 r_a
->status
= status
;
274 /*************************************************************************
276 *************************************************************************/
278 uint32
_net_auth_2(pipes_struct
*p
, NET_Q_AUTH_2
*q_u
, NET_R_AUTH_2
*r_u
)
280 uint32 status
= NT_STATUS_NOPROBLEMO
;
285 if (!get_valid_user_struct(p
->vuid
))
286 return NT_STATUS_NO_SUCH_USER
;
290 /* check that the client credentials are valid */
291 if (cred_assert(&q_u
->clnt_chal
, p
->dc
.sess_key
, &p
->dc
.clnt_cred
.challenge
, srv_time
)) {
293 /* create server challenge for inclusion in the reply */
294 cred_create(p
->dc
.sess_key
, &p
->dc
.srv_cred
.challenge
, srv_time
, &srv_cred
);
296 /* copy the received client credentials for use next time */
297 memcpy(p
->dc
.clnt_cred
.challenge
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
298 memcpy(p
->dc
.srv_cred
.challenge
.data
, q_u
->clnt_chal
.data
, sizeof(q_u
->clnt_chal
.data
));
300 status
= NT_STATUS_ACCESS_DENIED
;
303 srv_flgs
.neg_flags
= 0x000001ff;
305 /* set up the LSA AUTH 2 response */
306 init_net_r_auth_2(r_u
, &srv_cred
, &srv_flgs
, status
);
311 /*************************************************************************
313 *************************************************************************/
315 uint32
_net_srv_pwset(pipes_struct
*p
, NET_Q_SRV_PWSET
*q_u
, NET_R_SRV_PWSET
*r_u
)
317 uint32 status
= NT_STATUS_WRONG_PASSWORD
;
320 SAM_ACCOUNT
*sampass
=NULL
;
322 unsigned char pwd
[16];
325 if (!get_valid_user_struct(p
->vuid
))
326 return NT_STATUS_NO_SUCH_USER
;
328 /* checks and updates credentials. creates reply credentials */
329 if (!deal_with_creds(p
->dc
.sess_key
, &p
->dc
.clnt_cred
, &q_u
->clnt_id
.cred
, &srv_cred
))
330 return NT_STATUS_INVALID_HANDLE
;
332 memcpy(&p
->dc
.srv_cred
, &p
->dc
.clnt_cred
, sizeof(p
->dc
.clnt_cred
));
334 DEBUG(5,("_net_srv_pwset: %d\n", __LINE__
));
336 pstrcpy(mach_acct
, dos_unistrn2(q_u
->clnt_id
.login
.uni_acct_name
.buffer
,
337 q_u
->clnt_id
.login
.uni_acct_name
.uni_str_len
));
339 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct
));
341 pdb_init_sam(&sampass
);
344 ret
=pdb_getsampwnam(sampass
, mach_acct
);
347 /* Ensure the account exists and is a machine account. */
349 if (ret
==False
|| !(pdb_get_acct_ctrl(sampass
) & ACB_WSTRUST
)) {
350 pdb_free_sam(sampass
);
351 return NT_STATUS_NO_SUCH_USER
;
355 * Check the machine account name we're changing is the same
356 * as the one we've authenticated from. This prevents arbitrary
357 * machines changing other machine account passwords.
360 if (!strequal(mach_acct
, p
->dc
.mach_acct
)) {
361 pdb_free_sam(sampass
);
362 return NT_STATUS_ACCESS_DENIED
;
366 DEBUG(100,("Server password set : new given value was :\n"));
367 for(i
= 0; i
< 16; i
++)
368 DEBUG(100,("%02X ", q_u
->pwd
[i
]));
371 cred_hash3( pwd
, q_u
->pwd
, p
->dc
.sess_key
, 0);
373 /* lies! nt and lm passwords are _not_ the same: don't care */
374 pdb_set_lanman_passwd (sampass
, pwd
);
375 pdb_set_nt_passwd (sampass
, pwd
);
376 pdb_set_acct_ctrl (sampass
, ACB_WSTRUST
);
379 ret
= pdb_update_sam_account (sampass
,False
);
383 status
= NT_STATUS_NOPROBLEMO
;
385 /* set up the LSA Server Password Set response */
386 init_net_r_srv_pwset(r_u
, &srv_cred
, status
);
388 pdb_free_sam(sampass
);
393 /*************************************************************************
395 *************************************************************************/
397 uint32
_net_sam_logoff(pipes_struct
*p
, NET_Q_SAM_LOGOFF
*q_u
, NET_R_SAM_LOGOFF
*r_u
)
401 if (!get_valid_user_struct(p
->vuid
))
402 return NT_STATUS_NO_SUCH_USER
;
404 /* checks and updates credentials. creates reply credentials */
405 if (!deal_with_creds(p
->dc
.sess_key
, &p
->dc
.clnt_cred
,
406 &q_u
->sam_id
.client
.cred
, &srv_cred
))
407 return NT_STATUS_INVALID_HANDLE
;
409 memcpy(&p
->dc
.srv_cred
, &p
->dc
.clnt_cred
, sizeof(p
->dc
.clnt_cred
));
411 /* XXXX maybe we want to say 'no', reject the client's credentials */
412 r_u
->buffer_creds
= 1; /* yes, we have valid server credentials */
413 memcpy(&r_u
->srv_creds
, &srv_cred
, sizeof(r_u
->srv_creds
));
415 r_u
->status
= NT_STATUS_NOPROBLEMO
;
420 /*************************************************************************
421 net_login_interactive:
422 *************************************************************************/
424 static uint32
net_login_interactive(NET_ID_INFO_1
*id1
, SAM_ACCOUNT
*sampass
, pipes_struct
*p
)
430 unsigned char key
[16];
433 memcpy(key
, p
->dc
.sess_key
, 8);
435 memcpy(lm_pwd
, id1
->lm_owf
.data
, 16);
436 memcpy(nt_pwd
, id1
->nt_owf
.data
, 16);
438 #ifdef DEBUG_PASSWORD
440 dump_data(100, (char *)key
, 16);
442 DEBUG(100,("lm owf password:"));
443 dump_data(100, lm_pwd
, 16);
445 DEBUG(100,("nt owf password:"));
446 dump_data(100, nt_pwd
, 16);
449 SamOEMhash((uchar
*)lm_pwd
, key
, False
);
450 SamOEMhash((uchar
*)nt_pwd
, key
, False
);
452 #ifdef DEBUG_PASSWORD
453 DEBUG(100,("decrypt of lm owf password:"));
454 dump_data(100, lm_pwd
, 16);
456 DEBUG(100,("decrypt of nt owf password:"));
457 dump_data(100, nt_pwd
, 16);
460 if (memcmp(pdb_get_lanman_passwd(sampass
), lm_pwd
, 16) != 0 ||
461 memcmp(pdb_get_nt_passwd(sampass
), nt_pwd
, 16) != 0) {
462 status
= NT_STATUS_WRONG_PASSWORD
;
468 /*************************************************************************
470 *************************************************************************/
472 static uint32
net_login_network(NET_ID_INFO_2
*id2
, SAM_ACCOUNT
*sampass
)
474 uint8
*nt_pwd
, *lanman_pwd
;
476 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
477 id2
->hdr_lm_chal_resp
.str_str_len
,
478 id2
->hdr_nt_chal_resp
.str_str_len
));
480 /* JRA. Check the NT password first if it exists - this is a higher quality
481 password, if it exists and it doesn't match - fail. */
483 nt_pwd
= pdb_get_nt_passwd(sampass
);
484 lanman_pwd
= pdb_get_lanman_passwd(sampass
);
486 if (id2
->hdr_nt_chal_resp
.str_str_len
== 24 && nt_pwd
) {
487 if(smb_password_check((char *)id2
->nt_chal_resp
.buffer
,
488 nt_pwd
, id2
->lm_chal
))
489 return NT_STATUS_NOPROBLEMO
;
491 return NT_STATUS_WRONG_PASSWORD
;
494 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
495 if that is to be done, first move this entire function into a
496 library routine that calls the two smb_password_check() functions.
497 if disabling LM hashes (which nt can do for security reasons) then
498 an attempt should be made to disable them everywhere (which nt does
499 not do, for various security-hole reasons).
502 if (id2
->hdr_lm_chal_resp
.str_str_len
== 24 && lanman_pwd
&&
503 smb_password_check((char *)id2
->lm_chal_resp
.buffer
,
504 lanman_pwd
, id2
->lm_chal
))
505 return NT_STATUS_NOPROBLEMO
;
507 /* oops! neither password check succeeded */
509 return NT_STATUS_WRONG_PASSWORD
;
512 /*************************************************************************
514 *************************************************************************/
516 uint32
_net_sam_logon(pipes_struct
*p
, NET_Q_SAM_LOGON
*q_u
, NET_R_SAM_LOGON
*r_u
)
518 uint32 status
= NT_STATUS_NOPROBLEMO
;
519 NET_USER_INFO_3
*usr_info
= NULL
;
521 SAM_ACCOUNT
*sampass
= NULL
;
523 UNISTR2
*uni_samlogon_user
= NULL
;
527 usr_info
= (NET_USER_INFO_3
*)talloc(p
->mem_ctx
, sizeof(NET_USER_INFO_3
));
529 return NT_STATUS_NO_MEMORY
;
531 ZERO_STRUCTP(usr_info
);
533 if (!get_valid_user_struct(p
->vuid
))
534 return NT_STATUS_NO_SUCH_USER
;
536 /* checks and updates credentials. creates reply credentials */
537 if (!deal_with_creds(p
->dc
.sess_key
, &p
->dc
.clnt_cred
, &q_u
->sam_id
.client
.cred
, &srv_cred
))
538 return NT_STATUS_INVALID_HANDLE
;
540 memcpy(&p
->dc
.srv_cred
, &p
->dc
.clnt_cred
, sizeof(p
->dc
.clnt_cred
));
542 r_u
->buffer_creds
= 1; /* yes, we have valid server credentials */
543 memcpy(&r_u
->srv_creds
, &srv_cred
, sizeof(r_u
->srv_creds
));
545 /* store the user information, if there is any. */
546 r_u
->user
= usr_info
;
547 r_u
->switch_value
= 0; /* indicates no info */
548 r_u
->auth_resp
= 1; /* authoritative response */
549 r_u
->switch_value
= 3; /* indicates type of validation user info */
551 /* find the username */
553 switch (q_u
->sam_id
.logon_level
) {
554 case INTERACTIVE_LOGON_TYPE
:
555 uni_samlogon_user
= &q_u
->sam_id
.ctr
->auth
.id1
.uni_user_name
;
557 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
560 uni_samlogon_user
= &q_u
->sam_id
.ctr
->auth
.id2
.uni_user_name
;
562 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
565 DEBUG(2,("SAM Logon: unsupported switch value\n"));
566 return NT_STATUS_INVALID_INFO_CLASS
;
569 /* check username exists */
571 pstrcpy(nt_username
, dos_unistrn2(uni_samlogon_user
->buffer
, uni_samlogon_user
->uni_str_len
));
573 DEBUG(3,("User:[%s]\n", nt_username
));
576 * Convert to a UNIX username.
579 map_username(nt_username
);
581 pdb_init_sam(&sampass
);
583 /* get the account information */
585 ret
= pdb_getsampwnam(sampass
, nt_username
);
589 pdb_free_sam(sampass
);
590 return NT_STATUS_NO_SUCH_USER
;
593 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
595 if (acct_ctrl
& ACB_DISABLED
) {
596 pdb_free_sam(sampass
);
597 return NT_STATUS_ACCOUNT_DISABLED
;
600 /* Validate password - if required. */
602 if (!(acct_ctrl
& ACB_PWNOTREQ
)) {
603 switch (q_u
->sam_id
.logon_level
) {
604 case INTERACTIVE_LOGON_TYPE
:
605 /* interactive login. */
606 status
= net_login_interactive(&q_u
->sam_id
.ctr
->auth
.id1
, sampass
, p
);
609 /* network login. lm challenge and 24 byte responses */
610 status
= net_login_network(&q_u
->sam_id
.ctr
->auth
.id2
, sampass
);
615 if (status
!= NT_STATUS_NOPROBLEMO
) {
616 pdb_free_sam(sampass
);
620 /* lkclXXXX this is the point at which, if the login was
621 successful, that the SAM Local Security Authority should
622 record that the user is logged in to the domain.
626 DOM_GID
*gids
= NULL
;
629 pstring my_workgroup
;
630 pstring domain_groups
;
632 /* set up pointer indicating user/password failed to be found */
633 usr_info
->ptr_user_info
= 0;
635 /* XXXX hack to get standard_sub_basic() to use sam logon username */
636 /* possibly a better way would be to do a become_user() call */
637 sam_logon_in_ssb
= True
;
638 pstrcpy(samlogon_user
, nt_username
);
640 pstrcpy(my_workgroup
, lp_workgroup());
641 pstrcpy(my_name
, global_myname
);
645 * This is the point at which we get the group
646 * database - we should be getting the gid_t list
647 * from /etc/group and then turning the uids into
648 * rids and then into machine sids for this user.
652 get_domain_user_groups(domain_groups
, nt_username
);
655 * make_dom_gids allocates the gids array. JRA.
658 num_gids
= make_dom_gids(p
->mem_ctx
, domain_groups
, &gids
);
660 sam_logon_in_ssb
= False
;
662 init_net_user_info3(p
->mem_ctx
, usr_info
, sampass
,
664 0, /* bad_pw_count */
665 num_gids
, /* uint32 num_groups */
666 gids
, /* DOM_GID *gids */
667 0x20 , /* uint32 user_flgs (?) */
668 NULL
, /* char sess_key[16] */
669 my_name
, /* char *logon_srv */
670 my_workgroup
, /* char *logon_dom */
671 &global_sam_sid
, /* DOM_SID *dom_sid */
672 NULL
); /* char *other_sids */
674 pdb_free_sam(sampass
);