f266e937de6094ae222dc711eaed3c60b29c4cb4
[samba.git] / source3 / passdb / smbpasschange.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    change a password in a local smbpasswd file
5    Copyright (C) Andrew Tridgell 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24
25 /*************************************************************
26 add a new user to the local smbpasswd file
27 *************************************************************/
28 static BOOL add_new_user(char *user_name, uid_t uid,
29                                 uint16 acb_info,
30                                 uchar *new_p16, uchar *new_nt_p16)
31 {
32         struct smb_passwd new_smb_pwent;
33
34         pwdb_init_smb(&new_smb_pwent);
35
36         /* Create a new smb passwd entry and set it to the given password. */
37         new_smb_pwent.unix_uid = uid;
38         new_smb_pwent.nt_name = user_name; 
39         new_smb_pwent.smb_passwd = NULL;
40         new_smb_pwent.smb_nt_passwd = NULL;
41         new_smb_pwent.acct_ctrl = acb_info;
42         
43         if (IS_BITS_CLR_ALL(acb_info, ACB_DISABLED | ACB_PWNOTREQ))
44         {
45                 new_smb_pwent.smb_passwd = new_p16;
46                 new_smb_pwent.smb_nt_passwd = new_nt_p16;
47         }
48         
49         return add_smbpwd_entry(&new_smb_pwent);
50 }
51
52
53 /*************************************************************
54 change a password entry in the local smbpasswd file.
55
56 when modifying an account, set acb_mask to those bits that
57 require changing (to zero or one) and set acb_info to the
58 value required in those bits.  all bits NOT set in acb_mask
59 will NOT be modified.
60
61 when _adding_ an account, acb_mask must be set to 0xFFFF and
62 it is ignored, btw :-)
63
64 *************************************************************/
65 BOOL local_password_change(char *user_name,
66                                 BOOL add_user,
67                                 uint16 acb_info, uint16 acb_mask,
68                                 char *new_passwd, 
69                                 char *err_str, size_t err_str_len,
70                                 char *msg_str, size_t msg_str_len)
71 {
72         struct passwd  *pwd;
73         struct smb_passwd *smb_pwent;
74         static struct smb_passwd new_pwent;
75         static uchar           new_p16[16];
76         static uchar           new_nt_p16[16];
77         fstring unix_name;
78         uid_t unix_uid;
79
80         *err_str = '\0';
81         *msg_str = '\0';
82
83         pwd = getpwnam(user_name);
84         
85         /*
86          * Check for a trust account.
87          */
88         
89         if ((acb_info & acb_mask) != acb_info)
90         {
91                 slprintf(err_str, err_str_len - 1, "programmer error: acb_info (%x) requests bits to be set outside of acb_mask (%x) range\n", acb_info, acb_mask);
92         }
93
94         if (pwd == NULL)
95         {
96                 if (!IS_BITS_SET_ALL(acb_info, ACB_NORMAL))
97                 {
98                         slprintf(err_str, err_str_len - 1, "User %s does not \
99 exist in system password file (usually /etc/passwd).  \
100 Cannot add trust account without a valid system user.\n", user_name);
101                 }
102                 else
103                 {
104                         slprintf(err_str, err_str_len - 1, "User %s does not \
105 exist in system password file (usually /etc/passwd).\n", user_name);
106                 }
107                 return False;
108         }
109
110         unix_uid = pwd->pw_uid;
111         fstrcpy(unix_name, pwd->pw_name);
112
113         /* Calculate the MD4 hash (NT compatible) of the new password. */
114         nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
115
116         /* Get the smb passwd entry for this user */
117         smb_pwent = getsmbpwnam(user_name);
118         if (smb_pwent == NULL)
119         {
120                 if (!add_user)
121                 {
122                         slprintf(err_str, err_str_len-1,
123                                 "Failed to find entry for user %s.\n", unix_name);
124                         return False;
125                 }
126
127                 if (add_new_user(user_name, unix_uid, acb_info,
128                                  new_p16, new_nt_p16))
129                 {
130                         slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name);
131                         return True;
132                 }
133                 else
134                 {
135                         slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name);
136                         return False;
137                 }
138         }
139         else
140         {
141                 /* the entry already existed */
142                 add_user = False;
143         }
144
145         /*
146          * We are root - just write the new password
147          * and the valid last change time.
148          */
149
150         memcpy(&new_pwent, smb_pwent, sizeof(new_pwent));
151         new_pwent.nt_name = user_name; 
152         new_pwent.acct_ctrl &= ~acb_mask;
153         new_pwent.acct_ctrl |= (acb_info & acb_mask);
154         new_pwent.smb_passwd = NULL;
155         new_pwent.smb_nt_passwd = NULL;
156
157         if (IS_BITS_CLR_ALL(acb_info, ACB_DISABLED | ACB_PWNOTREQ))
158         {
159                 new_pwent.smb_passwd = new_p16;
160                 new_pwent.smb_nt_passwd = new_nt_p16;
161         }
162         
163         if (!mod_smbpwd_entry(&new_pwent, True))
164         {
165                 slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n",
166                         unix_name);
167                 return False;
168         }
169
170         return True;
171 }