Merge of new 2.2 code into HEAD (Gerald I hate you :-) :-). Allows new SAMR
[tprouty/samba.git] / source / rpc_server / srv_netlog_nt.c
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.
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 int DEBUGLEVEL;
30
31 extern BOOL sam_logon_in_ssb;
32 extern pstring samlogon_user;
33 extern pstring global_myname;
34 extern DOM_SID global_sam_sid;
35
36 /*************************************************************************
37  init_net_r_req_chal:
38  *************************************************************************/
39
40 static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
41                                 DOM_CHAL *srv_chal, int status)
42 {
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;
46 }
47
48 /*************************************************************************
49  error messages cropping up when using nltest.exe...
50  *************************************************************************/
51
52 #define ERROR_NO_SUCH_DOMAIN   0x54b
53 #define ERROR_NO_LOGON_SERVERS 0x51f
54
55 /*************************************************************************
56  net_reply_logon_ctrl2:
57  *************************************************************************/
58
59 uint32 _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
60 {
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";
67
68         DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
69
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);
74
75         DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
76
77         return r_u->status;
78 }
79
80 /*************************************************************************
81  net_reply_trust_dom_list:
82  *************************************************************************/
83
84 uint32 _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
85 {
86         char *trusted_domain = "test_domain";
87         uint32 num_trust_domains = 1;
88
89         DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
90
91         /* set up the Trusted Domain List response */
92         init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
93
94         DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
95
96         return r_u->status;
97 }
98
99 /*************************************************************************
100  init_net_r_auth_2:
101  *************************************************************************/
102
103 static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
104                               DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
105 {
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;
109 }
110
111 /***********************************************************************************
112  init_net_r_srv_pwset:
113  ***********************************************************************************/
114
115 static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
116                              DOM_CRED *srv_cred, int status)  
117 {
118         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
119
120         memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
121         r_s->status = status;
122
123         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
124 }
125
126 /******************************************************************
127  gets a machine password entry.  checks access rights of the host.
128  ******************************************************************/
129
130 static BOOL get_md4pw(char *md4pw, char *mach_acct)
131 {
132         SAM_ACCOUNT *sampass = NULL;
133         BYTE *pass;
134
135 #if 0
136     /*
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.
143      */
144
145         if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
146                           client_name(), client_addr()))
147         {
148                 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
149                 return False;
150         }
151 #endif /* 0 */
152
153         become_root();
154         sampass = pdb_getsampwnam(mach_acct);
155         unbecome_root();
156  
157         if ((sampass) != NULL && !(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) &&
158                 ((pass=pdb_get_nt_passwd(sampass)) != NULL))
159         {
160                 memcpy(md4pw, pass, 16);
161                 dump_data(5, md4pw, 16);
162  
163                 return True;
164         }
165
166         DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
167         return False;
168 }
169
170 /*************************************************************************
171  _net_req_chal
172  *************************************************************************/
173
174 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
175 {
176         uint32 status = NT_STATUS_NOPROBLEMO;
177         fstring mach_acct;
178         user_struct *vuser;
179
180         if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
181                 return False;
182
183         fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
184                                     q_u->uni_logon_clnt.uni_str_len));
185
186         strlower(mach_acct);
187         fstrcat(mach_acct, "$");
188
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));
193
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);
197
198                 memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8);
199
200                 memset((char *)vuser->dc.sess_key, '\0', sizeof(vuser->dc.sess_key));
201
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);
205         } else {
206                 /* lkclXXXX take a guess at a good error message to return :-) */
207                 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
208         }
209
210         /* set up the LSA REQUEST CHALLENGE response */
211         init_net_r_req_chal(r_u, &vuser->dc.srv_chal, status);
212
213         return r_u->status;
214 }
215
216 /*************************************************************************
217  _net_auth_2
218  *************************************************************************/
219
220 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
221 {
222         uint32 status = NT_STATUS_NOPROBLEMO;
223         DOM_CHAL srv_cred;
224         UTIME srv_time;
225         NEG_FLAGS srv_flgs;
226         user_struct *vuser;
227
228         if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
229                 return NT_STATUS_NO_SUCH_USER;
230
231         srv_time.time = 0;
232
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)) {
235
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);
238
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));
242         } else {
243                 status = NT_STATUS_ACCESS_DENIED;
244         }
245
246         srv_flgs.neg_flags = 0x000001ff;
247
248         /* set up the LSA AUTH 2 response */
249         init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
250
251         return r_u->status;
252 }
253
254 /*************************************************************************
255  _net_srv_pwset
256  *************************************************************************/
257
258 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
259 {
260         uint16 vuid = p->vuid;
261         uint32 status = NT_STATUS_WRONG_PASSWORD;
262         DOM_CRED srv_cred;
263         pstring mach_acct;
264         SAM_ACCOUNT *sampass;
265         BOOL ret = False;
266         user_struct *vuser;
267         unsigned char pwd[16];
268         int i;
269
270         if ((vuser = get_valid_user_struct(vuid)) == NULL)
271                 return NT_STATUS_NO_SUCH_USER;
272
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;
276
277         memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
278
279         DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
280
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));
283
284         DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
285
286         become_root();
287         sampass = pdb_getsampwnam(mach_acct);
288         unbecome_root();
289
290         if (sampass == NULL)
291                 return NT_STATUS_NO_SUCH_USER;
292
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]));
296         DEBUG(100,("\n"));
297
298         cred_hash3( pwd, q_u->pwd, vuser->dc.sess_key, 0);
299
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);
304  
305         become_root();
306         ret = pdb_update_sam_account (sampass,False);
307         unbecome_root();
308  
309         if (ret)
310                 status = NT_STATUS_NOPROBLEMO;
311
312         /* set up the LSA Server Password Set response */
313         init_net_r_srv_pwset(r_u, &srv_cred, status);
314
315         return r_u->status;
316 }
317
318
319 /*************************************************************************
320  _net_sam_logoff:
321  *************************************************************************/
322
323 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
324 {
325         DOM_CRED srv_cred;
326
327         user_struct *vuser;
328
329         if ((vuser = get_valid_user_struct(p->vuid)) == NULL)
330                 return NT_STATUS_NO_SUCH_USER;
331
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;
336
337         memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
338
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));
342
343         r_u->status = NT_STATUS_NOPROBLEMO;
344
345         return r_u->status;
346 }
347
348 /*************************************************************************
349  net_login_interactive:
350  *************************************************************************/
351
352 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, user_struct *vuser)
353 {
354         uint32 status = 0x0;
355
356         char nt_pwd[16];
357         char lm_pwd[16];
358         unsigned char key[16];
359
360         memset(key, 0, 16);
361         memcpy(key, vuser->dc.sess_key, 8);
362
363         memcpy(lm_pwd, id1->lm_owf.data, 16);
364         memcpy(nt_pwd, id1->nt_owf.data, 16);
365
366 #ifdef DEBUG_PASSWORD
367         DEBUG(100,("key:"));
368         dump_data(100, (char *)key, 16);
369
370         DEBUG(100,("lm owf password:"));
371         dump_data(100, lm_pwd, 16);
372
373         DEBUG(100,("nt owf password:"));
374         dump_data(100, nt_pwd, 16);
375 #endif
376
377         SamOEMhash((uchar *)lm_pwd, key, False);
378         SamOEMhash((uchar *)nt_pwd, key, False);
379
380 #ifdef DEBUG_PASSWORD
381         DEBUG(100,("decrypt of lm owf password:"));
382         dump_data(100, lm_pwd, 16);
383
384         DEBUG(100,("decrypt of nt owf password:"));
385         dump_data(100, nt_pwd, 16);
386 #endif
387
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;
391         }
392
393         return status;
394 }
395
396 /*************************************************************************
397  _net_login_network:
398  *************************************************************************/
399
400 static uint32 net_login_network(NET_ID_INFO_2 *id2, SAM_ACCOUNT *sampass)
401 {
402         BYTE    *nt_pwd, *lanman_pwd;
403
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));
407
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. */
410
411         nt_pwd = pdb_get_nt_passwd(sampass);
412         lanman_pwd = pdb_get_lanman_passwd(sampass);
413
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;
418                 else
419                         return NT_STATUS_WRONG_PASSWORD;
420         }
421
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).
428          */
429
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;
434
435         /* oops! neither password check succeeded */
436
437         return NT_STATUS_WRONG_PASSWORD;
438 }
439
440 /*************************************************************************
441  _net_sam_logon
442  *************************************************************************/
443
444 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
445 {
446         uint32 status = NT_STATUS_NOPROBLEMO;
447     uint16 vuid = p->vuid;
448     NET_USER_INFO_3 *usr_info = NULL;
449     DOM_CRED srv_cred;
450     SAM_ACCOUNT *sampass = NULL;
451         uint16 acct_ctrl;
452     UNISTR2 *uni_samlogon_user = NULL;
453     fstring nt_username;
454     user_struct *vuser = NULL;
455    
456         usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
457         if (!usr_info)
458                 return NT_STATUS_NO_MEMORY;
459         ZERO_STRUCTP(usr_info);
460  
461     if ((vuser = get_valid_user_struct(vuid)) == NULL)
462         return NT_STATUS_NO_SUCH_USER;
463     
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;
467     else
468         memcpy(&vuser->dc.srv_cred, &vuser->dc.clnt_cred, sizeof(vuser->dc.clnt_cred));
469     
470     /* find the username */
471     
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;
475             
476                 DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
477                 break;
478         case NET_LOGON_TYPE:
479                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
480             
481                 DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
482                 break;
483         default:
484                 DEBUG(2,("SAM Logon: unsupported switch value\n"));
485                 return NT_STATUS_INVALID_INFO_CLASS;
486         } /* end switch */
487
488         /* check username exists */
489
490         pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
491
492         DEBUG(3,("User:[%s]\n", nt_username));
493         
494         /*
495          * Convert to a UNIX username.
496          */
497
498         map_username(nt_username);
499
500         /* get the account information */
501         become_root();
502         sampass = pdb_getsampwnam(nt_username);
503         unbecome_root();
504
505         if (sampass == NULL)
506                 return NT_STATUS_NO_SUCH_USER;
507
508         acct_ctrl = pdb_get_acct_ctrl(sampass);
509
510         if (acct_ctrl & ACB_DISABLED)
511                 return NT_STATUS_ACCOUNT_DISABLED;
512     
513         /* Validate password - if required. */
514     
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);
520                         break;
521                 case NET_LOGON_TYPE:
522                         /* network login.  lm challenge and 24 byte responses */
523                         status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
524                         break;
525                 }
526         }
527     
528         if (status != NT_STATUS_NOPROBLEMO)
529                 return status;
530
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.
534         */
535     
536         {
537                 DOM_GID *gids = NULL;
538                 int num_gids = 0;
539                 pstring my_name;
540                 pstring my_workgroup;
541                 pstring domain_groups;
542         
543                 /* set up pointer indicating user/password failed to be found */
544                 usr_info->ptr_user_info = 0;
545         
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);
550
551                 pstrcpy(my_workgroup, lp_workgroup());
552                 pstrcpy(my_name, global_myname);
553                 strupper(my_name);
554
555                 /*
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.
560                  * JRA.
561                  */
562         
563                 get_domain_user_groups(domain_groups, nt_username);
564         
565                 /*
566                  * make_dom_gids allocates the gids array. JRA.
567                  */
568                 gids = NULL;
569                 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
570         
571                 sam_logon_in_ssb = False;
572         
573         init_net_user_info3(p->mem_ctx, usr_info, sampass,
574                             0, /* logon_count */
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 */
584     }
585
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));
589
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 */
594         else
595                 r_u->switch_value = 0; /* indicates no info */
596
597         r_u->status = status;
598         r_u->auth_resp = 1; /* authoritative response */
599
600     return r_u->status;
601 }