Moved cruft out of smb.h into ntdomain.h where it belongs. dc struct
[kai/samba.git] / source3 / 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         uint8 *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         /* JRA. This is ok as it is only used for generating the challenge. */
154
155         become_root();
156         sampass = pdb_getsampwnam(mach_acct);
157         unbecome_root();
158  
159         if ((sampass) != NULL && !(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) &&
160                 ((pass=pdb_get_nt_passwd(sampass)) != NULL))
161         {
162                 memcpy(md4pw, pass, 16);
163                 dump_data(5, md4pw, 16);
164  
165                 return True;
166         }
167
168         DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
169         return False;
170 }
171
172 /*************************************************************************
173  _net_req_chal
174  *************************************************************************/
175
176 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
177 {
178         uint32 status = NT_STATUS_NOPROBLEMO;
179         fstring mach_acct;
180
181         if (!get_valid_user_struct(p->vuid))
182                 return NT_STATUS_NO_SUCH_USER;
183
184         fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
185                                     q_u->uni_logon_clnt.uni_str_len));
186
187         strlower(mach_acct);
188         fstrcat(mach_acct, "$");
189
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));
194
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);
198
199                 memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
200
201                 memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
202
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);
206
207                 /* Save the machine account name. */
208                 fstrcpy(p->dc.mach_acct, mach_acct);
209
210         } else {
211                 /* lkclXXXX take a guess at a good error message to return :-) */
212                 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
213         }
214
215         /* set up the LSA REQUEST CHALLENGE response */
216         init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
217
218         return r_u->status;
219 }
220
221 /*************************************************************************
222  _net_auth_2
223  *************************************************************************/
224
225 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
226 {
227         uint32 status = NT_STATUS_NOPROBLEMO;
228         DOM_CHAL srv_cred;
229         UTIME srv_time;
230         NEG_FLAGS srv_flgs;
231
232         if (!get_valid_user_struct(p->vuid))
233                 return NT_STATUS_NO_SUCH_USER;
234
235         srv_time.time = 0;
236
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)) {
239
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);
242
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;
248         }
249
250         srv_flgs.neg_flags = 0x000001ff;
251
252         /* set up the LSA AUTH 2 response */
253         init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
254
255         return r_u->status;
256 }
257
258 /*************************************************************************
259  _net_srv_pwset
260  *************************************************************************/
261
262 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
263 {
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;
271
272         if (!get_valid_user_struct(p->vuid))
273                 return NT_STATUS_NO_SUCH_USER;
274
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;
278
279         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
280
281         DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
282
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));
285
286         DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
287
288         become_root();
289         sampass = pdb_getsampwnam(mach_acct);
290         unbecome_root();
291
292         /* Ensure the account exists and is a machine account. */
293
294         if (sampass == NULL || !(pdb_get_acct_ctrl(sampass) & ACB_WSTRUST))
295                 return NT_STATUS_NO_SUCH_USER;
296
297         /*
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.
301          */
302
303         if (!strequal(mach_acct, p->dc.mach_acct))
304                 return NT_STATUS_ACCESS_DENIED;
305
306         
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"));
311
312         cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
313
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);
318  
319         become_root();
320         ret = pdb_update_sam_account (sampass,False);
321         unbecome_root();
322  
323         if (ret)
324                 status = NT_STATUS_NOPROBLEMO;
325
326         /* set up the LSA Server Password Set response */
327         init_net_r_srv_pwset(r_u, &srv_cred, status);
328
329         return r_u->status;
330 }
331
332
333 /*************************************************************************
334  _net_sam_logoff:
335  *************************************************************************/
336
337 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
338 {
339         DOM_CRED srv_cred;
340
341         if (!get_valid_user_struct(p->vuid))
342                 return NT_STATUS_NO_SUCH_USER;
343
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;
348
349         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
350
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));
354
355         r_u->status = NT_STATUS_NOPROBLEMO;
356
357         return r_u->status;
358 }
359
360 /*************************************************************************
361  net_login_interactive:
362  *************************************************************************/
363
364 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, pipes_struct *p)
365 {
366         uint32 status = 0x0;
367
368         char nt_pwd[16];
369         char lm_pwd[16];
370         unsigned char key[16];
371
372         memset(key, 0, 16);
373         memcpy(key, p->dc.sess_key, 8);
374
375         memcpy(lm_pwd, id1->lm_owf.data, 16);
376         memcpy(nt_pwd, id1->nt_owf.data, 16);
377
378 #ifdef DEBUG_PASSWORD
379         DEBUG(100,("key:"));
380         dump_data(100, (char *)key, 16);
381
382         DEBUG(100,("lm owf password:"));
383         dump_data(100, lm_pwd, 16);
384
385         DEBUG(100,("nt owf password:"));
386         dump_data(100, nt_pwd, 16);
387 #endif
388
389         SamOEMhash((uchar *)lm_pwd, key, False);
390         SamOEMhash((uchar *)nt_pwd, key, False);
391
392 #ifdef DEBUG_PASSWORD
393         DEBUG(100,("decrypt of lm owf password:"));
394         dump_data(100, lm_pwd, 16);
395
396         DEBUG(100,("decrypt of nt owf password:"));
397         dump_data(100, nt_pwd, 16);
398 #endif
399
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;
403         }
404
405         return status;
406 }
407
408 /*************************************************************************
409  _net_login_network:
410  *************************************************************************/
411
412 static uint32 net_login_network(NET_ID_INFO_2 *id2, SAM_ACCOUNT *sampass)
413 {
414         uint8    *nt_pwd, *lanman_pwd;
415
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));
419
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. */
422
423         nt_pwd = pdb_get_nt_passwd(sampass);
424         lanman_pwd = pdb_get_lanman_passwd(sampass);
425
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;
432         }
433
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).
440          */
441
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;
446
447         /* oops! neither password check succeeded */
448
449         return NT_STATUS_WRONG_PASSWORD;
450 }
451
452 /*************************************************************************
453  _net_sam_logon
454  *************************************************************************/
455
456 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
457 {
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;
465    
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);
470  
471     if (!get_valid_user_struct(p->vuid))
472         return NT_STATUS_NO_SUCH_USER;
473     
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));
479     
480     /* find the username */
481     
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;
485             
486                 DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
487                 break;
488         case NET_LOGON_TYPE:
489                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
490             
491                 DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
492                 break;
493         default:
494                 DEBUG(2,("SAM Logon: unsupported switch value\n"));
495                 return NT_STATUS_INVALID_INFO_CLASS;
496         } /* end switch */
497
498         /* check username exists */
499
500         pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
501
502         DEBUG(3,("User:[%s]\n", nt_username));
503         
504         /*
505          * Convert to a UNIX username.
506          */
507
508         map_username(nt_username);
509
510         /* get the account information */
511         become_root();
512         sampass = pdb_getsampwnam(nt_username);
513         unbecome_root();
514
515         if (sampass == NULL)
516                 return NT_STATUS_NO_SUCH_USER;
517
518         acct_ctrl = pdb_get_acct_ctrl(sampass);
519
520         if (acct_ctrl & ACB_DISABLED)
521                 return NT_STATUS_ACCOUNT_DISABLED;
522     
523         /* Validate password - if required. */
524     
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);
530                         break;
531                 case NET_LOGON_TYPE:
532                         /* network login.  lm challenge and 24 byte responses */
533                         status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
534                         break;
535                 }
536         }
537     
538         if (status != NT_STATUS_NOPROBLEMO)
539                 return status;
540
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.
544         */
545     
546         {
547                 DOM_GID *gids = NULL;
548                 int num_gids = 0;
549                 pstring my_name;
550                 pstring my_workgroup;
551                 pstring domain_groups;
552         
553                 /* set up pointer indicating user/password failed to be found */
554                 usr_info->ptr_user_info = 0;
555         
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);
560
561                 pstrcpy(my_workgroup, lp_workgroup());
562                 pstrcpy(my_name, global_myname);
563                 strupper(my_name);
564
565                 /*
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.
570                  * JRA.
571                  */
572         
573                 get_domain_user_groups(domain_groups, nt_username);
574         
575                 /*
576                  * make_dom_gids allocates the gids array. JRA.
577                  */
578                 gids = NULL;
579                 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
580         
581                 sam_logon_in_ssb = False;
582         
583         init_net_user_info3(p->mem_ctx, usr_info, sampass,
584                             0, /* logon_count */
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 */
594     }
595
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));
599
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 */
604         else
605                 r_u->switch_value = 0; /* indicates no info */
606
607         r_u->status = status;
608         r_u->auth_resp = 1; /* authoritative response */
609
610     return r_u->status;
611 }