Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[ira/wip.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  *  Copyirht  (C) Andrew Bartlett                   2001.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *  
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *  
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 /* This is the implementation of the netlogon pipe. */
27
28 #include "includes.h"
29
30 extern BOOL sam_logon_in_ssb;
31 extern pstring samlogon_user;
32 extern pstring global_myname;
33 extern DOM_SID global_sam_sid;
34
35 /*************************************************************************
36  init_net_r_req_chal:
37  *************************************************************************/
38
39 static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
40                                 DOM_CHAL *srv_chal, NTSTATUS status)
41 {
42         DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
43         memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
44         r_c->status = status;
45 }
46
47 /*************************************************************************
48  error messages cropping up when using nltest.exe...
49  *************************************************************************/
50
51 #define ERROR_NO_SUCH_DOMAIN   0x54b
52 #define ERROR_NO_LOGON_SERVERS 0x51f
53
54 /*************************************************************************
55  net_reply_logon_ctrl:
56  *************************************************************************/
57
58 /* Some flag values reverse engineered from NLTEST.EXE */
59
60 #define LOGON_CTRL_IN_SYNC          0x00
61 #define LOGON_CTRL_REPL_NEEDED      0x01
62 #define LOGON_CTRL_REPL_IN_PROGRESS 0x02
63
64 NTSTATUS _net_logon_ctrl(pipes_struct *p, NET_Q_LOGON_CTRL *q_u, 
65                        NET_R_LOGON_CTRL *r_u)
66 {
67         uint32 flags = 0x0;
68         uint32 pdc_connection_status = 0x00; /* Maybe a win32 error code? */
69         
70         /* Setup the Logon Control response */
71
72         init_net_r_logon_ctrl(r_u, q_u->query_level, flags, 
73                               pdc_connection_status);
74
75         return r_u->status;
76 }
77
78 /****************************************************************************
79 Send a message to smbd to do a sam synchronisation
80 **************************************************************************/
81 static void send_sync_message(void)
82 {
83         TDB_CONTEXT *tdb;
84
85         tdb = tdb_open_log(lock_path("connections.tdb"), 0,
86                            TDB_DEFAULT, O_RDONLY, 0);
87
88         if (!tdb) {
89                 DEBUG(3, ("send_sync_message(): failed to open connections "
90                           "database\n"));
91                 return;
92         }
93
94         DEBUG(3, ("sending sam synchronisation message\n"));
95         
96         message_send_all(tdb, MSG_SMB_SAM_SYNC, NULL, 0, False);
97
98         tdb_close(tdb);
99 }
100
101 /*************************************************************************
102  net_reply_logon_ctrl2:
103  *************************************************************************/
104
105 NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
106 {
107         uint32 flags = 0x0;
108         uint32 pdc_connection_status = 0x0;
109         uint32 logon_attempts = 0x0;
110         uint32 tc_status = ERROR_NO_LOGON_SERVERS;
111         char *trusted_domain = "test_domain";
112
113         DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n",
114                   q_u->function_code, q_u->query_level, q_u->switch_value));
115
116         DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
117
118
119         /* set up the Logon Control2 response */
120         init_net_r_logon_ctrl2(r_u, q_u->query_level,
121                                flags, pdc_connection_status, logon_attempts,
122                                tc_status, trusted_domain);
123
124         if (lp_server_role() == ROLE_DOMAIN_BDC)
125                 send_sync_message();
126
127         DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
128
129         return r_u->status;
130 }
131
132 /*************************************************************************
133  net_reply_trust_dom_list:
134  *************************************************************************/
135
136 NTSTATUS _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
137 {
138         char *trusted_domain = "test_domain";
139         uint32 num_trust_domains = 1;
140
141         DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
142
143         /* set up the Trusted Domain List response */
144         init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
145
146         DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
147
148         return r_u->status;
149 }
150
151 /***********************************************************************************
152  init_net_r_srv_pwset:
153  ***********************************************************************************/
154
155 static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
156                              DOM_CRED *srv_cred, NTSTATUS status)  
157 {
158         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
159
160         memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
161         r_s->status = status;
162
163         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
164 }
165
166 /******************************************************************
167  gets a machine password entry.  checks access rights of the host.
168  ******************************************************************/
169
170 static BOOL get_md4pw(char *md4pw, char *mach_acct)
171 {
172         SAM_ACCOUNT *sampass = NULL;
173         uint8 *pass;
174         BOOL ret;
175
176 #if 0
177     /*
178      * Currently this code is redundent as we already have a filter
179      * by hostname list. What this code really needs to do is to 
180      * get a hosts allowed/hosts denied list from the SAM database
181      * on a per user basis, and make the access decision there.
182      * I will leave this code here for now as a reminder to implement
183      * this at a later date. JRA.
184      */
185
186         if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
187                           client_name(), client_addr()))
188         {
189                 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
190                 return False;
191         }
192 #endif /* 0 */
193
194         if(!pdb_init_sam(&sampass))
195                 return False;
196
197         /* JRA. This is ok as it is only used for generating the challenge. */
198         become_root();
199         ret=pdb_getsampwnam(sampass, mach_acct);
200         unbecome_root();
201  
202         if (ret==False) {
203                 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
204                 pdb_free_sam(&sampass);
205                 return False;
206         }
207
208         if (!(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) && ((pass=pdb_get_nt_passwd(sampass)) != NULL)) {
209                 memcpy(md4pw, pass, 16);
210                 dump_data(5, md4pw, 16);
211                 pdb_free_sam(&sampass);
212                 return True;
213         }
214         
215         DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
216         pdb_free_sam(&sampass);
217         return False;
218
219 }
220
221 /*************************************************************************
222  _net_req_chal
223  *************************************************************************/
224
225 NTSTATUS _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
226 {
227         NTSTATUS status = NT_STATUS_OK;
228         fstring mach_acct;
229
230         if (!get_valid_user_struct(p->vuid))
231                 return NT_STATUS_NO_SUCH_USER;
232
233         rpcstr_pull(mach_acct,q_u->uni_logon_clnt.buffer,sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
234
235         strlower(mach_acct);
236         fstrcat(mach_acct, "$");
237
238         if (get_md4pw((char *)p->dc.md4pw, mach_acct)) {
239                 /* copy the client credentials */
240                 memcpy(p->dc.clnt_chal.data          , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
241                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
242
243                 /* create a server challenge for the client */
244                 /* Set these to random values. */
245                 generate_random_buffer(p->dc.srv_chal.data, 8, False);
246
247                 memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
248
249                 memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
250
251                 /* from client / server challenges and md4 password, generate sess key */
252                 cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
253                                  (char *)p->dc.md4pw, p->dc.sess_key);
254
255                 /* Save the machine account name. */
256                 fstrcpy(p->dc.mach_acct, mach_acct);
257
258         } else {
259                 /* lkclXXXX take a guess at a good error message to return :-) */
260                 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
261         }
262
263         /* set up the LSA REQUEST CHALLENGE response */
264         init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
265
266         return r_u->status;
267 }
268
269 /*************************************************************************
270  init_net_r_auth:
271  *************************************************************************/
272
273 static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, NTSTATUS status)
274 {
275         memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
276         r_a->status = status;
277 }
278
279 /*************************************************************************
280  _net_auth
281  *************************************************************************/
282
283 NTSTATUS _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
284 {
285         NTSTATUS status = NT_STATUS_OK;
286         DOM_CHAL srv_cred;
287         UTIME srv_time;
288
289         if (!get_valid_user_struct(p->vuid))
290                 return NT_STATUS_NO_SUCH_USER;
291
292         srv_time.time = 0;
293
294         /* check that the client credentials are valid */
295         if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
296
297                 /* create server challenge for inclusion in the reply */
298                 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
299
300                 /* copy the received client credentials for use next time */
301                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
302                 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
303         } else {
304                 status = NT_STATUS_ACCESS_DENIED;
305         }
306
307         /* set up the LSA AUTH 2 response */
308         init_net_r_auth(r_u, &srv_cred, status);
309
310         return r_u->status;
311 }
312
313 /*************************************************************************
314  init_net_r_auth_2:
315  *************************************************************************/
316
317 static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
318                               DOM_CHAL *resp_cred, NEG_FLAGS *flgs, NTSTATUS status)
319 {
320         memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
321         memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
322         r_a->status = status;
323 }
324
325 /*************************************************************************
326  _net_auth_2
327  *************************************************************************/
328
329 NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
330 {
331         NTSTATUS status = NT_STATUS_OK;
332         DOM_CHAL srv_cred;
333         UTIME srv_time;
334         NEG_FLAGS srv_flgs;
335
336         if (!get_valid_user_struct(p->vuid))
337                 return NT_STATUS_NO_SUCH_USER;
338
339         srv_time.time = 0;
340
341         /* check that the client credentials are valid */
342         if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
343
344                 /* create server challenge for inclusion in the reply */
345                 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
346
347                 /* copy the received client credentials for use next time */
348                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
349                 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
350         } else {
351                 status = NT_STATUS_ACCESS_DENIED;
352         }
353
354         srv_flgs.neg_flags = 0x000001ff;
355
356         /* set up the LSA AUTH 2 response */
357         init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
358
359         return r_u->status;
360 }
361
362 /*************************************************************************
363  _net_srv_pwset
364  *************************************************************************/
365
366 NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
367 {
368         NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
369         DOM_CRED srv_cred;
370         pstring mach_acct;
371         SAM_ACCOUNT *sampass=NULL;
372         BOOL ret = False;
373         unsigned char pwd[16];
374         int i;
375
376         if (!get_valid_user_struct(p->vuid))
377                 return NT_STATUS_NO_SUCH_USER;
378
379         /* checks and updates credentials.  creates reply credentials */
380         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
381                 return NT_STATUS_INVALID_HANDLE;
382
383         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
384
385         DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
386
387         rpcstr_pull(mach_acct,q_u->clnt_id.login.uni_acct_name.buffer,
388                         sizeof(mach_acct),q_u->clnt_id.login.uni_acct_name.uni_str_len*2,0);
389
390         DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
391         
392         /*
393          * Check the machine account name we're changing is the same
394          * as the one we've authenticated from. This prevents arbitrary
395          * machines changing other machine account passwords.
396          */
397
398         if (!strequal(mach_acct, p->dc.mach_acct)) {
399                 return NT_STATUS_ACCESS_DENIED;
400         }
401
402         pdb_init_sam(&sampass);
403
404         become_root();
405         ret=pdb_getsampwnam(sampass, mach_acct);
406         unbecome_root();
407
408         /* Ensure the account exists and is a machine account. */
409
410         if (ret==False || !(pdb_get_acct_ctrl(sampass) & ACB_WSTRUST)) {
411                 pdb_free_sam(&sampass);
412                 return NT_STATUS_NO_SUCH_USER;
413         }
414         
415         DEBUG(100,("Server password set : new given value was :\n"));
416         for(i = 0; i < 16; i++)
417                 DEBUG(100,("%02X ", q_u->pwd[i]));
418         DEBUG(100,("\n"));
419
420         cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
421
422         /* lies!  nt and lm passwords are _not_ the same: don't care */
423         if (!pdb_set_lanman_passwd (sampass, pwd)) {
424                 pdb_free_sam(&sampass);
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         if (!pdb_set_nt_passwd     (sampass, pwd)) {
429                 pdb_free_sam(&sampass);
430                 return NT_STATUS_NO_MEMORY;
431         }
432
433         if (!pdb_set_acct_ctrl     (sampass, ACB_WSTRUST)) {
434                 pdb_free_sam(&sampass);
435                 /* Not quite sure what this one qualifies as, but this will do */
436                 return NT_STATUS_NO_MEMORY; 
437         }
438  
439         become_root();
440         ret = pdb_update_sam_account (sampass,False);
441         unbecome_root();
442  
443         if (ret)
444                 status = NT_STATUS_OK;
445
446         /* set up the LSA Server Password Set response */
447         init_net_r_srv_pwset(r_u, &srv_cred, status);
448
449         pdb_free_sam(&sampass);
450         return r_u->status;
451 }
452
453
454 /*************************************************************************
455  _net_sam_logoff:
456  *************************************************************************/
457
458 NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
459 {
460         DOM_CRED srv_cred;
461
462         if (!get_valid_user_struct(p->vuid))
463                 return NT_STATUS_NO_SUCH_USER;
464
465         /* checks and updates credentials.  creates reply credentials */
466         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, 
467                         &q_u->sam_id.client.cred, &srv_cred))
468                 return NT_STATUS_INVALID_HANDLE;
469
470         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
471
472         /* XXXX maybe we want to say 'no', reject the client's credentials */
473         r_u->buffer_creds = 1; /* yes, we have valid server credentials */
474         memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
475
476         r_u->status = NT_STATUS_OK;
477
478         return r_u->status;
479 }
480
481 /*************************************************************************
482  _net_logon_any:  Use the new authentications subsystem to log in.
483  *************************************************************************/
484
485 static NTSTATUS _net_logon_any(NET_ID_INFO_CTR *ctr, char *user, char *domain, char *workstation, char *sess_key)
486 {
487         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
488
489         unsigned char local_lm_response[24];
490         unsigned char local_nt_response[24];
491
492         auth_usersupplied_info user_info;
493         auth_serversupplied_info server_info;
494         AUTH_STR ourdomain, theirdomain, smb_username, wksta_name;
495
496         DEBUG(5, ("_net_logon_any: entered with user %s and domain %s\n", user, domain));
497                 
498         ZERO_STRUCT(user_info);
499         ZERO_STRUCT(server_info);
500         ZERO_STRUCT(ourdomain);
501         ZERO_STRUCT(theirdomain);
502         ZERO_STRUCT(smb_username);
503         ZERO_STRUCT(wksta_name);
504         
505         ourdomain.str = lp_workgroup();
506         ourdomain.len = strlen(ourdomain.str);
507
508         theirdomain.str = domain;
509         theirdomain.len = strlen(theirdomain.str);
510
511         user_info.requested_domain = theirdomain;
512         user_info.domain = ourdomain;
513         
514         smb_username.str = user;
515         smb_username.len = strlen(smb_username.str);
516
517         user_info.unix_username = smb_username;  /* For the time-being */
518         user_info.smb_username = smb_username;
519
520         user_info.wksta_name.str = workstation;
521         user_info.wksta_name.len = strlen(workstation);
522
523         user_info.wksta_name = wksta_name;
524
525         DEBUG(10,("_net_logon_any: Attempting validation level %d.\n", ctr->switch_value));
526         switch (ctr->switch_value) {
527         case NET_LOGON_TYPE:
528                 /* Standard challange/response authenticaion */
529
530                 user_info.lm_resp.buffer = (uint8 *)ctr->auth.id2.lm_chal_resp.buffer;
531                 user_info.lm_resp.len = ctr->auth.id2.lm_chal_resp.str_str_len;
532                 user_info.nt_resp.buffer = (uint8 *)ctr->auth.id2.nt_chal_resp.buffer;
533                 user_info.nt_resp.len = ctr->auth.id2.nt_chal_resp.str_str_len;
534                 memcpy(user_info.chal, ctr->auth.id2.lm_chal, 8);
535                 break;
536         case INTERACTIVE_LOGON_TYPE:
537                 /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted
538                    with the session key.  We will convert this to challange/responce for the 
539                    auth subsystem to chew on */
540         {
541                 char nt_pwd[16];
542                 char lm_pwd[16];
543                 unsigned char key[16];
544                 
545                 memset(key, 0, 16);
546                 memcpy(key, sess_key, 8);
547                 
548                 memcpy(lm_pwd, ctr->auth.id1.lm_owf.data, 16);
549                 memcpy(nt_pwd, ctr->auth.id1.nt_owf.data, 16);
550
551 #ifdef DEBUG_PASSWORD
552                 DEBUG(100,("key:"));
553                 dump_data(100, (char *)key, 16);
554                 
555                 DEBUG(100,("lm owf password:"));
556                 dump_data(100, lm_pwd, 16);
557                 
558                 DEBUG(100,("nt owf password:"));
559                 dump_data(100, nt_pwd, 16);
560 #endif
561                 
562                 SamOEMhash((uchar *)lm_pwd, key, 16);
563                 SamOEMhash((uchar *)nt_pwd, key, 16);
564                 
565 #ifdef DEBUG_PASSWORD
566                 DEBUG(100,("decrypt of lm owf password:"));
567                 dump_data(100, lm_pwd, 16);
568                 
569                 DEBUG(100,("decrypt of nt owf password:"));
570                 dump_data(100, nt_pwd, 16);
571 #endif
572
573                 generate_random_buffer(user_info.chal, 8, False);
574                 SMBOWFencrypt((const unsigned char *)lm_pwd, user_info.chal, local_lm_response);
575                 SMBOWFencrypt((const unsigned char *)nt_pwd, user_info.chal, local_nt_response);
576                 user_info.lm_resp.buffer = (uint8 *)local_lm_response;
577                 user_info.lm_resp.len = 24;
578                 user_info.nt_resp.buffer = (uint8 *)local_nt_response;
579                 user_info.nt_resp.len = 24;
580                 break;
581         }
582         default:
583                 DEBUG(2,("SAM Logon: unsupported switch value\n"));
584                 return NT_STATUS_INVALID_INFO_CLASS;
585         } /* end switch */
586         
587         nt_status = check_password(&user_info, &server_info);
588
589         DEBUG(5, ("_net_logon_any: exited with status %s\n", 
590                   get_nt_error_msg(nt_status)));
591
592         return nt_status;
593 }
594
595
596
597 /*************************************************************************
598  _net_sam_logon
599  *************************************************************************/
600
601 NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
602 {
603         NTSTATUS status = NT_STATUS_OK;
604         NET_USER_INFO_3 *usr_info = NULL;
605         DOM_CRED srv_cred;
606         SAM_ACCOUNT *sampass = NULL;
607         UNISTR2 *uni_samlogon_user = NULL;
608         UNISTR2 *uni_samlogon_domain = NULL;
609         UNISTR2 *uni_samlogon_workstation = NULL;
610         fstring nt_username, nt_domain, nt_workstation;
611         
612         BOOL ret;
613
614         usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
615         if (!usr_info)
616                 return NT_STATUS_NO_MEMORY;
617
618         ZERO_STRUCTP(usr_info);
619  
620         if (!get_valid_user_struct(p->vuid))
621                 return NT_STATUS_NO_SUCH_USER;
622     
623         /* checks and updates credentials.  creates reply credentials */
624         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
625                 return NT_STATUS_INVALID_HANDLE;
626         else
627                 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
628     
629         r_u->buffer_creds = 1; /* yes, we have valid server credentials */
630         memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
631
632         /* store the user information, if there is any. */
633         r_u->user = usr_info;
634         r_u->switch_value = 0; /* indicates no info */
635         r_u->auth_resp = 1; /* authoritative response */
636         r_u->switch_value = 3; /* indicates type of validation user info */
637
638         /* find the username */
639     
640         switch (q_u->sam_id.logon_level) {
641         case INTERACTIVE_LOGON_TYPE:
642                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
643                 uni_samlogon_domain = &q_u->sam_id.ctr->auth.id1.uni_domain_name;
644                 uni_samlogon_workstation = &q_u->sam_id.ctr->auth.id1.uni_wksta_name;
645             
646                 DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
647                 break;
648         case NET_LOGON_TYPE:
649                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
650                 uni_samlogon_domain = &q_u->sam_id.ctr->auth.id2.uni_domain_name;
651                 uni_samlogon_workstation = &q_u->sam_id.ctr->auth.id2.uni_wksta_name;
652             
653                 DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
654                 break;
655         default:
656                 DEBUG(2,("SAM Logon: unsupported switch value\n"));
657                 return NT_STATUS_INVALID_INFO_CLASS;
658         } /* end switch */
659
660         /* check username exists */
661
662         rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0);
663         rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
664         rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);
665
666         DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, 
667                  nt_workstation, nt_domain));
668         
669         /*
670          * Convert to a UNIX username.
671          */
672
673         map_username(nt_username);
674
675         DEBUG(10,("Attempting validation level %d for mapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username));
676
677         status = _net_logon_any(q_u->sam_id.ctr, nt_username, nt_domain, nt_workstation, (char *)p->dc.sess_key);
678
679         /* Check account and password */
680     
681         if (NT_STATUS_IS_ERR(status))
682                 return status;
683
684         pdb_init_sam(&sampass);
685
686         /* get the account information */
687         become_root();
688         ret = pdb_getsampwnam(sampass, nt_username);
689         unbecome_root();
690
691         if (ret == False) {
692                 pdb_free_sam(&sampass);
693                 return NT_STATUS_NO_SUCH_USER;
694         }
695         
696         /* This is the point at which, if the login was successful, that
697            the SAM Local Security Authority should record that the user is
698            logged in to the domain.  */
699     
700         {
701                 DOM_GID *gids = NULL;
702                 int num_gids = 0;
703                 pstring my_name;
704                 pstring my_workgroup;
705                 pstring domain_groups;
706         
707                 /* set up pointer indicating user/password failed to be found */
708                 usr_info->ptr_user_info = 0;
709         
710                 /* XXXX hack to get standard_sub_basic() to use sam logon username */
711                 /* possibly a better way would be to do a become_user() call */
712                 sam_logon_in_ssb = True;
713                 pstrcpy(samlogon_user, nt_username);
714
715                 pstrcpy(my_workgroup, lp_workgroup());
716                 pstrcpy(my_name, global_myname);
717                 strupper(my_name);
718
719                 /*
720                  * This is the point at which we get the group
721                  * database - we should be getting the gid_t list
722                  * from /etc/group and then turning the uids into
723                  * rids and then into machine sids for this user.
724                  * JRA.
725                  */
726         
727                 get_domain_user_groups(domain_groups, nt_username);
728         
729                 /*
730                  * make_dom_gids allocates the gids array. JRA.
731                  */
732                 gids = NULL;
733                 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
734         
735                 sam_logon_in_ssb = False;
736         
737                 init_net_user_info3(p->mem_ctx, usr_info, sampass,
738                             0, /* logon_count */
739                             0, /* bad_pw_count */
740                             num_gids,    /* uint32 num_groups */
741                             gids    , /* DOM_GID *gids */
742                             0x20    , /* uint32 user_flgs (?) */
743                             NULL, /* char sess_key[16] */
744                             my_name     , /* char *logon_srv */
745                             my_workgroup, /* char *logon_dom */
746                             &global_sam_sid,     /* DOM_SID *dom_sid */
747                             NULL); /* char *other_sids */
748         }
749         pdb_free_sam(&sampass);
750         return status;
751 }