Based on an original PAM patch by Andrew Bartlett, re-written by me to
[Samba.git] / source / rpc_server / srv_netlog_nt.c
blobfa6b945815219996c781f001dbcd99a0a184e880
1 /*
2 * Unix SMB/Netbios implementation.
3 * Version 1.9.
4 * RPC Pipe client / server routines
5 * Copyright (C) Andrew Tridgell 1992-1997,
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
7 * Copyright (C) Paul Ashton 1997.
8 * Copyright (C) Jeremy Allison 1998-2001.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* This is the implementation of the netlogon pipe. */
27 #include "includes.h"
29 extern int DEBUGLEVEL;
31 extern BOOL sam_logon_in_ssb;
32 extern pstring samlogon_user;
33 extern pstring global_myname;
34 extern DOM_SID global_sam_sid;
36 /*************************************************************************
37 init_net_r_req_chal:
38 *************************************************************************/
40 static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
41 DOM_CHAL *srv_chal, int status)
43 DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
44 memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
45 r_c->status = status;
48 /*************************************************************************
49 error messages cropping up when using nltest.exe...
50 *************************************************************************/
52 #define ERROR_NO_SUCH_DOMAIN 0x54b
53 #define ERROR_NO_LOGON_SERVERS 0x51f
55 /*************************************************************************
56 net_reply_logon_ctrl2:
57 *************************************************************************/
59 uint32 _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
61 /* lkclXXXX - guess what - absolutely no idea what these are! */
62 uint32 flags = 0x0;
63 uint32 pdc_connection_status = 0x0;
64 uint32 logon_attempts = 0x0;
65 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
66 char *trusted_domain = "test_domain";
68 DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
70 /* set up the Logon Control2 response */
71 init_r_logon_ctrl2(r_u, q_u->query_level,
72 flags, pdc_connection_status, logon_attempts,
73 tc_status, trusted_domain);
75 DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
77 return r_u->status;
80 /*************************************************************************
81 net_reply_trust_dom_list:
82 *************************************************************************/
84 uint32 _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
86 char *trusted_domain = "test_domain";
87 uint32 num_trust_domains = 1;
89 DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
91 /* set up the Trusted Domain List response */
92 init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
94 DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
96 return r_u->status;
99 /***********************************************************************************
100 init_net_r_srv_pwset:
101 ***********************************************************************************/
103 static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
104 DOM_CRED *srv_cred, int status)
106 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
108 memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
109 r_s->status = status;
111 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
114 /******************************************************************
115 gets a machine password entry. checks access rights of the host.
116 ******************************************************************/
118 static BOOL get_md4pw(char *md4pw, char *mach_acct)
120 struct smb_passwd *smb_pass;
122 #if 0
124 * Currently this code is redundent as we already have a filter
125 * by hostname list. What this code really needs to do is to
126 * get a hosts allowed/hosts denied list from the SAM database
127 * on a per user basis, and make the access decision there.
128 * I will leave this code here for now as a reminder to implement
129 * this at a later date. JRA.
132 if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
133 client_name(), client_addr()))
135 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
136 return False;
138 #endif /* 0 */
140 /* JRA. This is ok as it is only used for generating the challenge. */
142 become_root();
143 smb_pass = getsmbpwnam(mach_acct);
144 unbecome_root();
146 if ((smb_pass) != NULL && !(smb_pass->acct_ctrl & ACB_DISABLED) &&
147 (smb_pass->smb_nt_passwd != NULL))
149 memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
150 dump_data(5, md4pw, 16);
152 return True;
154 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
155 return False;
158 /*************************************************************************
159 _net_req_chal
160 *************************************************************************/
162 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
164 uint32 status = NT_STATUS_NOPROBLEMO;
165 fstring mach_acct;
167 if (!get_valid_user_struct(p->vuid))
168 return NT_STATUS_NO_SUCH_USER;
170 fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
171 q_u->uni_logon_clnt.uni_str_len));
173 strlower(mach_acct);
174 fstrcat(mach_acct, "$");
176 if (get_md4pw((char *)p->dc.md4pw, mach_acct)) {
177 /* copy the client credentials */
178 memcpy(p->dc.clnt_chal.data , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
179 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
181 /* create a server challenge for the client */
182 /* Set these to random values. */
183 generate_random_buffer(p->dc.srv_chal.data, 8, False);
185 memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
187 memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
189 /* from client / server challenges and md4 password, generate sess key */
190 cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
191 (char *)p->dc.md4pw, p->dc.sess_key);
193 /* Save the machine account name. */
194 fstrcpy(p->dc.mach_acct, mach_acct);
196 } else {
197 /* lkclXXXX take a guess at a good error message to return :-) */
198 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
201 /* set up the LSA REQUEST CHALLENGE response */
202 init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
204 return r_u->status;
207 /*************************************************************************
208 init_net_r_auth:
209 *************************************************************************/
211 static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, int status)
213 memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
214 r_a->status = status;
217 /*************************************************************************
218 _net_auth
219 *************************************************************************/
221 uint32 _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
223 uint32 status = NT_STATUS_NOPROBLEMO;
224 DOM_CHAL srv_cred;
225 UTIME srv_time;
227 if (!get_valid_user_struct(p->vuid))
228 return NT_STATUS_NO_SUCH_USER;
230 srv_time.time = 0;
232 /* check that the client credentials are valid */
233 if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
235 /* create server challenge for inclusion in the reply */
236 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
238 /* copy the received client credentials for use next time */
239 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
240 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
241 } else {
242 status = NT_STATUS_ACCESS_DENIED;
245 /* set up the LSA AUTH 2 response */
246 init_net_r_auth(r_u, &srv_cred, status);
248 return r_u->status;
251 /*************************************************************************
252 init_net_r_auth_2:
253 *************************************************************************/
255 static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
256 DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
258 memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
259 memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
260 r_a->status = status;
263 /*************************************************************************
264 _net_auth_2
265 *************************************************************************/
267 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
269 uint32 status = NT_STATUS_NOPROBLEMO;
270 DOM_CHAL srv_cred;
271 UTIME srv_time;
272 NEG_FLAGS srv_flgs;
274 if (!get_valid_user_struct(p->vuid))
275 return NT_STATUS_NO_SUCH_USER;
277 srv_time.time = 0;
279 /* check that the client credentials are valid */
280 if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
282 /* create server challenge for inclusion in the reply */
283 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
285 /* copy the received client credentials for use next time */
286 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
287 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
288 } else {
289 status = NT_STATUS_ACCESS_DENIED;
292 srv_flgs.neg_flags = 0x000001ff;
294 /* set up the LSA AUTH 2 response */
295 init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
297 return r_u->status;
300 /*************************************************************************
301 _net_srv_pwset
302 *************************************************************************/
304 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
306 uint32 status = NT_STATUS_NOPROBLEMO;
307 DOM_CRED srv_cred;
308 pstring mach_acct;
309 struct smb_passwd *smb_pass;
310 BOOL ret;
311 unsigned char pwd[16];
312 int i;
314 if (!get_valid_user_struct(p->vuid))
315 return NT_STATUS_NO_SUCH_USER;
317 /* checks and updates credentials. creates reply credentials */
318 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
319 return NT_STATUS_INVALID_HANDLE;
321 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
323 DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
325 pstrcpy(mach_acct, dos_unistrn2(q_u->clnt_id.login.uni_acct_name.buffer,
326 q_u->clnt_id.login.uni_acct_name.uni_str_len));
329 * Check the machine account name we're changing is the same
330 * as the one we've authenticated from. This prevents arbitrary
331 * machines changing other machine account passwords.
334 if (!strequal(mach_acct, p->dc.mach_acct))
335 return NT_STATUS_ACCESS_DENIED;
337 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
339 become_root();
340 smb_pass = getsmbpwnam(mach_acct);
341 unbecome_root();
343 /* Ensure the account exists and is a machine account. */
344 if (smb_pass == NULL || !(smb_pass->acct_ctrl & ACB_WSTRUST))
345 return NT_STATUS_NO_SUCH_USER;
347 DEBUG(100,("Server password set : new given value was :\n"));
348 for(i = 0; i < 16; i++)
349 DEBUG(100,("%02X ", q_u->pwd[i]));
350 DEBUG(100,("\n"));
352 cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
354 /* lies! nt and lm passwords are _not_ the same: don't care */
355 smb_pass->smb_passwd = pwd;
356 smb_pass->smb_nt_passwd = pwd;
357 smb_pass->acct_ctrl = ACB_WSTRUST;
359 become_root();
360 ret = mod_smbpwd_entry(smb_pass,False);
361 unbecome_root();
363 if (!ret)
364 status = NT_STATUS_WRONG_PASSWORD;
366 /* set up the LSA Server Password Set response */
367 init_net_r_srv_pwset(r_u, &srv_cred, status);
369 return r_u->status;
373 /*************************************************************************
374 _net_sam_logoff:
375 *************************************************************************/
377 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
379 DOM_CRED srv_cred;
381 if (!get_valid_user_struct(p->vuid))
382 return NT_STATUS_NO_SUCH_USER;
384 /* checks and updates credentials. creates reply credentials */
385 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred,
386 &q_u->sam_id.client.cred, &srv_cred))
387 return NT_STATUS_INVALID_HANDLE;
389 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
391 /* XXXX maybe we want to say 'no', reject the client's credentials */
392 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
393 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
395 r_u->status = NT_STATUS_NOPROBLEMO;
397 return r_u->status;
400 /*************************************************************************
401 net_login_interactive:
402 *************************************************************************/
404 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, struct smb_passwd *smb_pass, pipes_struct *p)
406 uint32 status = 0x0;
408 char nt_pwd[16];
409 char lm_pwd[16];
410 unsigned char key[16];
412 memset(key, 0, 16);
413 memcpy(key, p->dc.sess_key, 8);
415 memcpy(lm_pwd, id1->lm_owf.data, 16);
416 memcpy(nt_pwd, id1->nt_owf.data, 16);
418 #ifdef DEBUG_PASSWORD
419 DEBUG(100,("key:"));
420 dump_data(100, (char *)key, 16);
422 DEBUG(100,("lm owf password:"));
423 dump_data(100, lm_pwd, 16);
425 DEBUG(100,("nt owf password:"));
426 dump_data(100, nt_pwd, 16);
427 #endif
429 SamOEMhash((uchar *)lm_pwd, key, False);
430 SamOEMhash((uchar *)nt_pwd, key, False);
432 #ifdef DEBUG_PASSWORD
433 DEBUG(100,("decrypt of lm owf password:"));
434 dump_data(100, lm_pwd, 16);
436 DEBUG(100,("decrypt of nt owf password:"));
437 dump_data(100, nt_pwd, 16);
438 #endif
440 if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 ||
441 memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
443 status = NT_STATUS_WRONG_PASSWORD;
446 return status;
449 /*************************************************************************
450 _net_login_network:
451 *************************************************************************/
453 static uint32 net_login_network(NET_ID_INFO_2 *id2, struct smb_passwd *smb_pass)
455 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
456 id2->hdr_lm_chal_resp.str_str_len,
457 id2->hdr_nt_chal_resp.str_str_len));
459 /* JRA. Check the NT password first if it exists - this is a higher quality
460 password, if it exists and it doesn't match - fail. */
462 if (id2->hdr_nt_chal_resp.str_str_len == 24 &&
463 smb_pass->smb_nt_passwd != NULL)
465 if(smb_password_check((char *)id2->nt_chal_resp.buffer,
466 smb_pass->smb_nt_passwd,
467 id2->lm_chal))
468 return NT_STATUS_NO_PROBLEMO;
469 else
470 return NT_STATUS_WRONG_PASSWORD;
473 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
474 if that is to be done, first move this entire function into a
475 library routine that calls the two smb_password_check() functions.
476 if disabling LM hashes (which nt can do for security reasons) then
477 an attempt should be made to disable them everywhere (which nt does
478 not do, for various security-hole reasons).
481 if (lp_lanman_auth() &&
482 id2->hdr_lm_chal_resp.str_str_len == 24 &&
483 smb_password_check((char *)id2->lm_chal_resp.buffer,
484 smb_pass->smb_passwd,
485 id2->lm_chal))
487 return NT_STATUS_NO_PROBLEMO;
491 /* oops! neither password check succeeded */
493 return NT_STATUS_WRONG_PASSWORD;
496 /*************************************************************************
497 _net_sam_logon
498 *************************************************************************/
500 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
502 uint32 status = NT_STATUS_NOPROBLEMO;
503 NET_USER_INFO_3 *usr_info = NULL;
504 DOM_CRED srv_cred;
505 struct smb_passwd *smb_pass = NULL;
506 struct sam_passwd *sam_pass = NULL;
507 UNISTR2 *uni_samlogon_user = NULL;
508 fstring nt_username;
510 usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
511 if (!usr_info)
512 return NT_STATUS_NO_MEMORY;
513 ZERO_STRUCTP(usr_info);
515 if (!get_valid_user_struct(p->vuid))
516 return NT_STATUS_NO_SUCH_USER;
518 /* checks and updates credentials. creates reply credentials */
519 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
520 return NT_STATUS_INVALID_HANDLE;
521 else
522 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
524 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
525 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
527 /* store the user information, if there is any. */
528 r_u->user = usr_info;
529 r_u->switch_value = 0; /* indicates no info */
530 r_u->auth_resp = 1; /* authoritative response */
531 r_u->switch_value = 3; /* indicates type of validation user info */
533 /* find the username */
535 switch (q_u->sam_id.logon_level) {
536 case INTERACTIVE_LOGON_TYPE:
537 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
539 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
540 break;
541 case NET_LOGON_TYPE:
542 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
544 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
545 break;
546 default:
547 DEBUG(2,("SAM Logon: unsupported switch value\n"));
548 return NT_STATUS_INVALID_INFO_CLASS;
549 } /* end switch */
551 /* check username exists */
553 pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
555 DEBUG(3,("User:[%s]\n", nt_username));
558 * Convert to a UNIX username.
561 map_username(nt_username);
564 * We previously called Get_Pwnam(ntusername, True) here which could
565 * have modified the case of the username. Beaware of this
566 * is the username case in smbpasswd does not match that in /etc/passwd
567 * and domain logons begin to fail. -- jerry
570 /* XXXX hack to get standard_sub_basic() to use sam logon username */
571 /* possibly a better way would be to do a become_user() call */
572 sam_logon_in_ssb = True;
573 pstrcpy(samlogon_user, nt_username);
575 become_root();
576 sam_pass = getsam21pwnam(nt_username);
577 unbecome_root();
578 smb_pass = pdb_sam_to_smb(sam_pass);
580 sam_logon_in_ssb = False;
582 if ((smb_pass=pdb_sam_to_smb(sam_pass)) == NULL)
583 return NT_STATUS_NO_SUCH_USER;
584 else if (smb_pass->acct_ctrl & ACB_DISABLED)
585 return NT_STATUS_ACCOUNT_DISABLED;
587 /* Validate password - if required. */
589 if (smb_pass->acct_ctrl & ACB_PWNOTREQ) {
590 if (!lp_null_passwords()) {
591 DEBUG(3,("Account for user %s has a null password and null passwords are NOT allowed",nt_username));
592 return NT_STATUS_ACCOUNT_DISABLED;
596 #ifdef WITH_PAM
597 become_root();
598 status = smb_pam_accountcheck(nt_username);
599 unbecome_root();
600 if (status != NT_STATUS_NOPROBLEMO)
601 return status;
602 #endif
604 if (!(smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
605 switch (q_u->sam_id.logon_level) {
606 case INTERACTIVE_LOGON_TYPE:
607 /* interactive login. */
608 status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, smb_pass, p);
609 break;
610 case NET_LOGON_TYPE:
611 /* network login. lm challenge and 24 byte responses */
612 status = net_login_network(&q_u->sam_id.ctr->auth.id2, smb_pass);
613 break;
617 if (status != NT_STATUS_NOPROBLEMO)
618 return status;
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.
625 /* return the profile plus other bits :-) */
628 DOM_GID *gids = NULL;
629 int num_gids = 0;
630 NTTIME dummy_time;
631 pstring my_name;
632 pstring my_workgroup;
633 pstring domain_groups;
634 uint32 r_uid;
635 uint32 r_gid;
637 /* set up pointer indicating user/password failed to be found */
638 usr_info->ptr_user_info = 0;
640 dummy_time.low = 0xffffffff;
641 dummy_time.high = 0x7fffffff;
643 pstrcpy(my_workgroup, lp_workgroup());
645 pstrcpy(my_name, global_myname);
646 strupper(my_name);
649 * This is the point at which we get the group
650 * database - we should be getting the gid_t list
651 * from /etc/group and then turning the uids into
652 * rids and then into machine sids for this user.
653 * JRA.
656 get_domain_user_groups(domain_groups, nt_username);
659 * make_dom_gids allocates the gids array. JRA.
661 gids = NULL;
662 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
664 if (pdb_name_to_rid(nt_username, &r_uid, &r_gid))
666 init_net_user_info3(p->mem_ctx, usr_info,
667 &dummy_time, /* logon_time */
668 &dummy_time, /* logoff_time */
669 &dummy_time, /* kickoff_time */
670 &dummy_time, /* pass_last_set_time */
671 &dummy_time, /* pass_can_change_time */
672 &dummy_time, /* pass_must_change_time */
674 nt_username , /* user_name */
675 sam_pass->full_name, /* full_name */
676 sam_pass->logon_script , /* logon_script */
677 sam_pass->profile_path , /* profile_path */
678 sam_pass->home_dir , /* home_dir */
679 sam_pass->dir_drive , /* dir_drive */
681 0, /* logon_count */
682 0, /* bad_pw_count */
684 r_uid , /* RID user_id */
685 r_gid , /* RID group_id */
686 num_gids, /* uint32 num_groups */
687 gids , /* DOM_GID *gids */
688 0x20 , /* uint32 user_flgs (?) */
690 NULL, /* char sess_key[16] */
692 my_name , /* char *logon_srv */
693 my_workgroup, /* char *logon_dom */
695 &global_sam_sid, /* DOM_SID *dom_sid */
696 NULL); /* char *other_sids */
698 else
700 return NT_STATUS_NO_SUCH_USER;
705 return status;