Big cleanup of passdb and backends.
[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  *
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_srv_pwset:
101  ***********************************************************************************/
102
103 static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
104                              DOM_CRED *srv_cred, int status)  
105 {
106         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
107
108         memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
109         r_s->status = status;
110
111         DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
112 }
113
114 /******************************************************************
115  gets a machine password entry.  checks access rights of the host.
116  ******************************************************************/
117
118 static BOOL get_md4pw(char *md4pw, char *mach_acct)
119 {
120         SAM_ACCOUNT *sampass = NULL;
121         uint8 *pass;
122         BOOL ret;
123
124 #if 0
125     /*
126      * Currently this code is redundent as we already have a filter
127      * by hostname list. What this code really needs to do is to 
128      * get a hosts allowed/hosts denied list from the SAM database
129      * on a per user basis, and make the access decision there.
130      * I will leave this code here for now as a reminder to implement
131      * this at a later date. JRA.
132      */
133
134         if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
135                           client_name(), client_addr()))
136         {
137                 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
138                 return False;
139         }
140 #endif /* 0 */
141
142         if(!pdb_init_sam(&sampass))
143                 return False;
144
145         /* JRA. This is ok as it is only used for generating the challenge. */
146         become_root();
147         ret=pdb_getsampwnam(sampass, mach_acct);
148         unbecome_root();
149  
150         if (ret==False) {
151                 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
152                 pdb_clear_sam(sampass);
153                 return False;
154         }
155
156         if (!(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) && ((pass=pdb_get_nt_passwd(sampass)) != NULL)) {
157                 memcpy(md4pw, pass, 16);
158                 dump_data(5, md4pw, 16);
159                 pdb_clear_sam(sampass);
160                 return True;
161         }
162         
163         DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
164         pdb_clear_sam(sampass);
165         return False;
166
167 }
168
169 /*************************************************************************
170  _net_req_chal
171  *************************************************************************/
172
173 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
174 {
175         uint32 status = NT_STATUS_NOPROBLEMO;
176         fstring mach_acct;
177
178         if (!get_valid_user_struct(p->vuid))
179                 return NT_STATUS_NO_SUCH_USER;
180
181         fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
182                                     q_u->uni_logon_clnt.uni_str_len));
183
184         strlower(mach_acct);
185         fstrcat(mach_acct, "$");
186
187         if (get_md4pw((char *)p->dc.md4pw, mach_acct)) {
188                 /* copy the client credentials */
189                 memcpy(p->dc.clnt_chal.data          , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
190                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
191
192                 /* create a server challenge for the client */
193                 /* Set these to random values. */
194                 generate_random_buffer(p->dc.srv_chal.data, 8, False);
195
196                 memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
197
198                 memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
199
200                 /* from client / server challenges and md4 password, generate sess key */
201                 cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
202                                  (char *)p->dc.md4pw, p->dc.sess_key);
203
204                 /* Save the machine account name. */
205                 fstrcpy(p->dc.mach_acct, mach_acct);
206
207         } else {
208                 /* lkclXXXX take a guess at a good error message to return :-) */
209                 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
210         }
211
212         /* set up the LSA REQUEST CHALLENGE response */
213         init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
214
215         return r_u->status;
216 }
217
218 /*************************************************************************
219  init_net_r_auth:
220  *************************************************************************/
221
222 static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, int status)
223 {
224         memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
225         r_a->status = status;
226 }
227
228 /*************************************************************************
229  _net_auth
230  *************************************************************************/
231
232 uint32 _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
233 {
234         uint32 status = NT_STATUS_NOPROBLEMO;
235         DOM_CHAL srv_cred;
236         UTIME srv_time;
237
238         if (!get_valid_user_struct(p->vuid))
239                 return NT_STATUS_NO_SUCH_USER;
240
241         srv_time.time = 0;
242
243         /* check that the client credentials are valid */
244         if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
245
246                 /* create server challenge for inclusion in the reply */
247                 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
248
249                 /* copy the received client credentials for use next time */
250                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
251                 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
252         } else {
253                 status = NT_STATUS_ACCESS_DENIED;
254         }
255
256         /* set up the LSA AUTH 2 response */
257         init_net_r_auth(r_u, &srv_cred, status);
258
259         return r_u->status;
260 }
261
262 /*************************************************************************
263  init_net_r_auth_2:
264  *************************************************************************/
265
266 static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
267                               DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
268 {
269         memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
270         memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
271         r_a->status = status;
272 }
273
274 /*************************************************************************
275  _net_auth_2
276  *************************************************************************/
277
278 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
279 {
280         uint32 status = NT_STATUS_NOPROBLEMO;
281         DOM_CHAL srv_cred;
282         UTIME srv_time;
283         NEG_FLAGS srv_flgs;
284
285         if (!get_valid_user_struct(p->vuid))
286                 return NT_STATUS_NO_SUCH_USER;
287
288         srv_time.time = 0;
289
290         /* check that the client credentials are valid */
291         if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
292
293                 /* create server challenge for inclusion in the reply */
294                 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
295
296                 /* copy the received client credentials for use next time */
297                 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
298                 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
299         } else {
300                 status = NT_STATUS_ACCESS_DENIED;
301         }
302
303         srv_flgs.neg_flags = 0x000001ff;
304
305         /* set up the LSA AUTH 2 response */
306         init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
307
308         return r_u->status;
309 }
310
311 /*************************************************************************
312  _net_srv_pwset
313  *************************************************************************/
314
315 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
316 {
317         uint32 status = NT_STATUS_WRONG_PASSWORD;
318         DOM_CRED srv_cred;
319         pstring mach_acct;
320         SAM_ACCOUNT *sampass=NULL;
321         BOOL ret = False;
322         unsigned char pwd[16];
323         int i;
324
325         if (!get_valid_user_struct(p->vuid))
326                 return NT_STATUS_NO_SUCH_USER;
327
328         /* checks and updates credentials.  creates reply credentials */
329         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
330                 return NT_STATUS_INVALID_HANDLE;
331
332         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
333
334         DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
335
336         pstrcpy(mach_acct, dos_unistrn2(q_u->clnt_id.login.uni_acct_name.buffer,
337                                     q_u->clnt_id.login.uni_acct_name.uni_str_len));
338
339         DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
340         
341         pdb_init_sam(&sampass);
342
343         become_root();
344         ret=pdb_getsampwnam(sampass, mach_acct);
345         unbecome_root();
346
347         /* Ensure the account exists and is a machine account. */
348
349         if (ret==False || !(pdb_get_acct_ctrl(sampass) & ACB_WSTRUST)) {
350                 pdb_clear_sam(sampass);
351                 return NT_STATUS_NO_SUCH_USER;
352         }
353
354         /*
355          * Check the machine account name we're changing is the same
356          * as the one we've authenticated from. This prevents arbitrary
357          * machines changing other machine account passwords.
358          */
359
360         if (!strequal(mach_acct, p->dc.mach_acct)) {
361                 pdb_clear_sam(sampass);
362                 return NT_STATUS_ACCESS_DENIED;
363         }
364
365         
366         DEBUG(100,("Server password set : new given value was :\n"));
367         for(i = 0; i < 16; i++)
368                 DEBUG(100,("%02X ", q_u->pwd[i]));
369         DEBUG(100,("\n"));
370
371         cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
372
373         /* lies!  nt and lm passwords are _not_ the same: don't care */
374         pdb_set_lanman_passwd (sampass, pwd);
375         pdb_set_nt_passwd     (sampass, pwd);
376         pdb_set_acct_ctrl     (sampass, ACB_WSTRUST);
377  
378         become_root();
379         ret = pdb_update_sam_account (sampass,False);
380         unbecome_root();
381  
382         if (ret)
383                 status = NT_STATUS_NOPROBLEMO;
384
385         /* set up the LSA Server Password Set response */
386         init_net_r_srv_pwset(r_u, &srv_cred, status);
387
388         pdb_clear_sam(sampass);
389         return r_u->status;
390 }
391
392
393 /*************************************************************************
394  _net_sam_logoff:
395  *************************************************************************/
396
397 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
398 {
399         DOM_CRED srv_cred;
400
401         if (!get_valid_user_struct(p->vuid))
402                 return NT_STATUS_NO_SUCH_USER;
403
404         /* checks and updates credentials.  creates reply credentials */
405         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, 
406                         &q_u->sam_id.client.cred, &srv_cred))
407                 return NT_STATUS_INVALID_HANDLE;
408
409         memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
410
411         /* XXXX maybe we want to say 'no', reject the client's credentials */
412         r_u->buffer_creds = 1; /* yes, we have valid server credentials */
413         memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
414
415         r_u->status = NT_STATUS_NOPROBLEMO;
416
417         return r_u->status;
418 }
419
420 /*************************************************************************
421  net_login_interactive:
422  *************************************************************************/
423
424 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, pipes_struct *p)
425 {
426         uint32 status = 0x0;
427
428         char nt_pwd[16];
429         char lm_pwd[16];
430         unsigned char key[16];
431
432         memset(key, 0, 16);
433         memcpy(key, p->dc.sess_key, 8);
434
435         memcpy(lm_pwd, id1->lm_owf.data, 16);
436         memcpy(nt_pwd, id1->nt_owf.data, 16);
437
438 #ifdef DEBUG_PASSWORD
439         DEBUG(100,("key:"));
440         dump_data(100, (char *)key, 16);
441
442         DEBUG(100,("lm owf password:"));
443         dump_data(100, lm_pwd, 16);
444
445         DEBUG(100,("nt owf password:"));
446         dump_data(100, nt_pwd, 16);
447 #endif
448
449         SamOEMhash((uchar *)lm_pwd, key, False);
450         SamOEMhash((uchar *)nt_pwd, key, False);
451
452 #ifdef DEBUG_PASSWORD
453         DEBUG(100,("decrypt of lm owf password:"));
454         dump_data(100, lm_pwd, 16);
455
456         DEBUG(100,("decrypt of nt owf password:"));
457         dump_data(100, nt_pwd, 16);
458 #endif
459
460         if (memcmp(pdb_get_lanman_passwd(sampass), lm_pwd, 16) != 0 ||
461             memcmp(pdb_get_nt_passwd(sampass), nt_pwd, 16) != 0) {
462                 status = NT_STATUS_WRONG_PASSWORD;
463         }
464
465         return status;
466 }
467
468 /*************************************************************************
469  _net_login_network:
470  *************************************************************************/
471
472 static uint32 net_login_network(NET_ID_INFO_2 *id2, SAM_ACCOUNT *sampass)
473 {
474         uint8    *nt_pwd, *lanman_pwd;
475
476         DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
477                 id2->hdr_lm_chal_resp.str_str_len, 
478                 id2->hdr_nt_chal_resp.str_str_len));
479
480         /* JRA. Check the NT password first if it exists - this is a higher quality 
481            password, if it exists and it doesn't match - fail. */
482
483         nt_pwd = pdb_get_nt_passwd(sampass);
484         lanman_pwd = pdb_get_lanman_passwd(sampass);
485
486         if (id2->hdr_nt_chal_resp.str_str_len == 24 && nt_pwd) {
487                 if(smb_password_check((char *)id2->nt_chal_resp.buffer,
488                                    nt_pwd, id2->lm_chal)) 
489                         return NT_STATUS_NOPROBLEMO;
490                 else
491                         return NT_STATUS_WRONG_PASSWORD;
492         }
493
494         /* lkclXXXX this is not a good place to put disabling of LM hashes in.
495            if that is to be done, first move this entire function into a
496            library routine that calls the two smb_password_check() functions.
497            if disabling LM hashes (which nt can do for security reasons) then
498            an attempt should be made to disable them everywhere (which nt does
499            not do, for various security-hole reasons).
500          */
501
502         if (id2->hdr_lm_chal_resp.str_str_len == 24 && lanman_pwd &&
503                 smb_password_check((char *)id2->lm_chal_resp.buffer,
504                                    lanman_pwd, id2->lm_chal))
505                 return NT_STATUS_NOPROBLEMO;
506
507         /* oops! neither password check succeeded */
508
509         return NT_STATUS_WRONG_PASSWORD;
510 }
511
512 /*************************************************************************
513  _net_sam_logon
514  *************************************************************************/
515
516 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
517 {
518         uint32 status = NT_STATUS_NOPROBLEMO;
519         NET_USER_INFO_3 *usr_info = NULL;
520         DOM_CRED srv_cred;
521         SAM_ACCOUNT *sampass = NULL;
522         uint16 acct_ctrl;
523         UNISTR2 *uni_samlogon_user = NULL;
524         fstring nt_username;
525         BOOL ret;
526    
527         usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
528         if (!usr_info)
529                 return NT_STATUS_NO_MEMORY;
530
531         ZERO_STRUCTP(usr_info);
532  
533         if (!get_valid_user_struct(p->vuid))
534                 return NT_STATUS_NO_SUCH_USER;
535     
536         /* checks and updates credentials.  creates reply credentials */
537         if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
538                 return NT_STATUS_INVALID_HANDLE;
539         else
540                 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
541     
542         r_u->buffer_creds = 1; /* yes, we have valid server credentials */
543         memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
544
545         /* store the user information, if there is any. */
546         r_u->user = usr_info;
547         r_u->switch_value = 0; /* indicates no info */
548         r_u->auth_resp = 1; /* authoritative response */
549         r_u->switch_value = 3; /* indicates type of validation user info */
550
551         /* find the username */
552     
553         switch (q_u->sam_id.logon_level) {
554         case INTERACTIVE_LOGON_TYPE:
555                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
556             
557                 DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
558                 break;
559         case NET_LOGON_TYPE:
560                 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
561             
562                 DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
563                 break;
564         default:
565                 DEBUG(2,("SAM Logon: unsupported switch value\n"));
566                 return NT_STATUS_INVALID_INFO_CLASS;
567         } /* end switch */
568
569         /* check username exists */
570
571         pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
572
573         DEBUG(3,("User:[%s]\n", nt_username));
574         
575         /*
576          * Convert to a UNIX username.
577          */
578
579         map_username(nt_username);
580
581         pdb_init_sam(&sampass);
582
583         /* get the account information */
584         become_root();
585         ret = pdb_getsampwnam(sampass, nt_username);
586         unbecome_root();
587
588         if (ret == False){
589                 pdb_clear_sam(sampass);
590                 return NT_STATUS_NO_SUCH_USER;
591         }
592
593         acct_ctrl = pdb_get_acct_ctrl(sampass);
594
595         if (acct_ctrl & ACB_DISABLED) {
596                 pdb_clear_sam(sampass);
597                 return NT_STATUS_ACCOUNT_DISABLED;
598         }
599     
600         /* Validate password - if required. */
601     
602         if (!(acct_ctrl & ACB_PWNOTREQ)) {
603                 switch (q_u->sam_id.logon_level) {
604                 case INTERACTIVE_LOGON_TYPE:
605                         /* interactive login. */
606                         status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, sampass, p);
607                         break;
608                 case NET_LOGON_TYPE:
609                         /* network login.  lm challenge and 24 byte responses */
610                         status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
611                         break;
612                 }
613         }
614     
615         if (status != NT_STATUS_NOPROBLEMO) {
616                 pdb_clear_sam(sampass);
617                 return status;
618         }
619
620         /* lkclXXXX this is the point at which, if the login was
621                 successful, that the SAM Local Security Authority should
622                 record that the user is logged in to the domain.
623         */
624     
625         {
626                 DOM_GID *gids = NULL;
627                 int num_gids = 0;
628                 pstring my_name;
629                 pstring my_workgroup;
630                 pstring domain_groups;
631         
632                 /* set up pointer indicating user/password failed to be found */
633                 usr_info->ptr_user_info = 0;
634         
635                 /* XXXX hack to get standard_sub_basic() to use sam logon username */
636                 /* possibly a better way would be to do a become_user() call */
637                 sam_logon_in_ssb = True;
638                 pstrcpy(samlogon_user, nt_username);
639
640                 pstrcpy(my_workgroup, lp_workgroup());
641                 pstrcpy(my_name, global_myname);
642                 strupper(my_name);
643
644                 /*
645                  * This is the point at which we get the group
646                  * database - we should be getting the gid_t list
647                  * from /etc/group and then turning the uids into
648                  * rids and then into machine sids for this user.
649                  * JRA.
650                  */
651         
652                 get_domain_user_groups(domain_groups, nt_username);
653         
654                 /*
655                  * make_dom_gids allocates the gids array. JRA.
656                  */
657                 gids = NULL;
658                 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
659         
660                 sam_logon_in_ssb = False;
661         
662                 init_net_user_info3(p->mem_ctx, usr_info, sampass,
663                             0, /* logon_count */
664                             0, /* bad_pw_count */
665                             num_gids,    /* uint32 num_groups */
666                             gids    , /* DOM_GID *gids */
667                             0x20    , /* uint32 user_flgs (?) */
668                             NULL, /* char sess_key[16] */
669                             my_name     , /* char *logon_srv */
670                             my_workgroup, /* char *logon_dom */
671                             &global_sam_sid,     /* DOM_SID *dom_sid */
672                             NULL); /* char *other_sids */
673         }
674         pdb_clear_sam(sampass);
675         return status;
676 }