make proto
[Samba/gbeck.git] / source / rpc_server / srv_netlog_nt.c
blobcfcfac1d1adbc06db009f74d8668e3b7597c66a1
1 /*
2 * Unix SMB/Netbios implementation.
3 * Version 1.9.
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. */
27 #include "includes.h"
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 /*************************************************************************
37 init_net_r_req_chal:
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));
45 r_c->status = status;
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! */
62 uint32 flags = 0x0;
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__));
77 return r_u->status;
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__));
96 return r_u->status;
99 /*************************************************************************
100 init_net_r_auth_2:
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;
133 uint8 *pass;
135 #if 0
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));
149 return False;
151 #endif /* 0 */
153 /* JRA. This is ok as it is only used for generating the challenge. */
155 become_root();
156 sampass = pdb_getsampwnam(mach_acct);
157 unbecome_root();
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);
165 return True;
168 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
169 return False;
172 /*************************************************************************
173 _net_req_chal
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;
179 fstring mach_acct;
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));
187 strlower(mach_acct);
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);
210 } else {
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);
218 return r_u->status;
221 /*************************************************************************
222 _net_auth_2
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;
228 DOM_CHAL srv_cred;
229 UTIME srv_time;
230 NEG_FLAGS srv_flgs;
232 if (!get_valid_user_struct(p->vuid))
233 return NT_STATUS_NO_SUCH_USER;
235 srv_time.time = 0;
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));
246 } else {
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);
255 return r_u->status;
258 /*************************************************************************
259 _net_srv_pwset
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;
265 DOM_CRED srv_cred;
266 pstring mach_acct;
267 SAM_ACCOUNT *sampass;
268 BOOL ret = False;
269 unsigned char pwd[16];
270 int i;
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));
288 become_root();
289 sampass = pdb_getsampwnam(mach_acct);
290 unbecome_root();
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]));
310 DEBUG(100,("\n"));
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);
319 become_root();
320 ret = pdb_update_sam_account (sampass,False);
321 unbecome_root();
323 if (ret)
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);
329 return r_u->status;
333 /*************************************************************************
334 _net_sam_logoff:
335 *************************************************************************/
337 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
339 DOM_CRED srv_cred;
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;
357 return r_u->status;
360 /*************************************************************************
361 net_login_interactive:
362 *************************************************************************/
364 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, pipes_struct *p)
366 uint32 status = 0x0;
368 char nt_pwd[16];
369 char lm_pwd[16];
370 unsigned char key[16];
372 memset(key, 0, 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
379 DEBUG(100,("key:"));
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);
387 #endif
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);
398 #endif
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;
405 return status;
408 /*************************************************************************
409 _net_login_network:
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;
430 else
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 /*************************************************************************
453 _net_sam_logon
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;
460 DOM_CRED srv_cred;
461 SAM_ACCOUNT *sampass = NULL;
462 uint16 acct_ctrl;
463 UNISTR2 *uni_samlogon_user = NULL;
464 fstring nt_username;
466 usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
467 if (!usr_info)
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;
477 else
478 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
480 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
481 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
483 /* store the user information, if there is any. */
484 r_u->user = usr_info;
485 r_u->switch_value = 0; /* indicates no info */
486 r_u->auth_resp = 1; /* authoritative response */
487 r_u->switch_value = 3; /* indicates type of validation user info */
489 /* find the username */
491 switch (q_u->sam_id.logon_level) {
492 case INTERACTIVE_LOGON_TYPE:
493 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
495 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
496 break;
497 case NET_LOGON_TYPE:
498 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
500 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
501 break;
502 default:
503 DEBUG(2,("SAM Logon: unsupported switch value\n"));
504 return NT_STATUS_INVALID_INFO_CLASS;
505 } /* end switch */
507 /* check username exists */
509 pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
511 DEBUG(3,("User:[%s]\n", nt_username));
514 * Convert to a UNIX username.
517 map_username(nt_username);
519 /* get the account information */
520 become_root();
521 sampass = pdb_getsampwnam(nt_username);
522 unbecome_root();
524 if (sampass == NULL)
525 return NT_STATUS_NO_SUCH_USER;
527 acct_ctrl = pdb_get_acct_ctrl(sampass);
529 if (acct_ctrl & ACB_DISABLED)
530 return NT_STATUS_ACCOUNT_DISABLED;
532 /* Validate password - if required. */
534 if (!(acct_ctrl & ACB_PWNOTREQ)) {
535 switch (q_u->sam_id.logon_level) {
536 case INTERACTIVE_LOGON_TYPE:
537 /* interactive login. */
538 status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, sampass, p);
539 break;
540 case NET_LOGON_TYPE:
541 /* network login. lm challenge and 24 byte responses */
542 status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
543 break;
547 if (status != NT_STATUS_NOPROBLEMO)
548 return status;
550 /* lkclXXXX this is the point at which, if the login was
551 successful, that the SAM Local Security Authority should
552 record that the user is logged in to the domain.
556 DOM_GID *gids = NULL;
557 int num_gids = 0;
558 pstring my_name;
559 pstring my_workgroup;
560 pstring domain_groups;
562 /* set up pointer indicating user/password failed to be found */
563 usr_info->ptr_user_info = 0;
565 /* XXXX hack to get standard_sub_basic() to use sam logon username */
566 /* possibly a better way would be to do a become_user() call */
567 sam_logon_in_ssb = True;
568 pstrcpy(samlogon_user, nt_username);
570 pstrcpy(my_workgroup, lp_workgroup());
571 pstrcpy(my_name, global_myname);
572 strupper(my_name);
575 * This is the point at which we get the group
576 * database - we should be getting the gid_t list
577 * from /etc/group and then turning the uids into
578 * rids and then into machine sids for this user.
579 * JRA.
582 get_domain_user_groups(domain_groups, nt_username);
585 * make_dom_gids allocates the gids array. JRA.
587 gids = NULL;
588 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
590 sam_logon_in_ssb = False;
592 init_net_user_info3(p->mem_ctx, usr_info, sampass,
593 0, /* logon_count */
594 0, /* bad_pw_count */
595 num_gids, /* uint32 num_groups */
596 gids , /* DOM_GID *gids */
597 0x20 , /* uint32 user_flgs (?) */
598 NULL, /* char sess_key[16] */
599 my_name , /* char *logon_srv */
600 my_workgroup, /* char *logon_dom */
601 &global_sam_sid, /* DOM_SID *dom_sid */
602 NULL); /* char *other_sids */
605 return status;