first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source / 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, BOOL trust_account, 
29                          BOOL disable_user, BOOL set_no_password,
30                          uchar *new_p16, uchar *new_nt_p16)
31 {
32         struct smb_passwd new_smb_pwent;
33
34         /* Create a new smb passwd entry and set it to the given password. */
35         new_smb_pwent.smb_userid = uid;
36         new_smb_pwent.smb_name = user_name; 
37         new_smb_pwent.smb_passwd = NULL;
38         new_smb_pwent.smb_nt_passwd = NULL;
39         new_smb_pwent.acct_ctrl = (trust_account ? ACB_WSTRUST : ACB_NORMAL);
40         
41         if(disable_user) {
42                 new_smb_pwent.acct_ctrl |= ACB_DISABLED;
43         } else if (set_no_password) {
44                 new_smb_pwent.acct_ctrl |= ACB_PWNOTREQ;
45         } else {
46                 new_smb_pwent.smb_passwd = new_p16;
47                 new_smb_pwent.smb_nt_passwd = new_nt_p16;
48         }
49         
50         return add_smbpwd_entry(&new_smb_pwent);
51 }
52
53
54 /*************************************************************
55 change a password entry in the local smbpasswd file
56 *************************************************************/
57
58 BOOL local_password_change(char *user_name, BOOL trust_account, BOOL add_user,
59                            BOOL enable_user, BOOL disable_user, BOOL set_no_password,
60                            char *new_passwd, 
61                            char *err_str, size_t err_str_len,
62                            char *msg_str, size_t msg_str_len)
63 {
64         struct passwd  *pwd;
65         void *vp;
66         struct smb_passwd *smb_pwent;
67         uchar           new_p16[16];
68         uchar           new_nt_p16[16];
69
70         *err_str = '\0';
71         *msg_str = '\0';
72
73         pwd = sys_getpwnam(user_name);
74         
75         /*
76          * Check for a local account.
77          */
78         
79         if(!pwd) {
80                 slprintf(err_str, err_str_len - 1, "User %s does not \
81 exist in system password file (usually /etc/passwd). Cannot add \
82 account without a valid local system user.\n", user_name);
83                 return False;
84         }
85
86         /* Calculate the MD4 hash (NT compatible) of the new password. */
87         nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
88
89         /*
90          * Open the smbpaswd file.
91          */
92         vp = startsmbpwent(True);
93         if (!vp && errno == ENOENT) {
94                 FILE *fp;
95                 slprintf(msg_str,msg_str_len-1,
96                         "smbpasswd file did not exist - attempting to create it.\n");
97                 fp = sys_fopen(lp_smb_passwd_file(), "w");
98                 if (fp) {
99                         fprintf(fp, "# Samba SMB password file\n");
100                         fclose(fp);
101                         vp = startsmbpwent(True);
102                 }
103         }
104
105         if (!vp) {
106                 slprintf(err_str, err_str_len-1, "Cannot open file %s. Error was %s\n",
107                         lp_smb_passwd_file(), strerror(errno) );
108                 return False;
109         }
110   
111         /* Get the smb passwd entry for this user */
112         smb_pwent = getsmbpwnam(user_name);
113         if (smb_pwent == NULL) {
114                 if(add_user == False) {
115                         slprintf(err_str, err_str_len-1,
116                                 "Failed to find entry for user %s.\n", pwd->pw_name);
117                         endsmbpwent(vp);
118                         return False;
119                 }
120
121                 if (add_new_user(user_name, pwd->pw_uid, trust_account, disable_user,
122                                  set_no_password, new_p16, new_nt_p16)) {
123                         slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name);
124                         endsmbpwent(vp);
125                         return True;
126                 } else {
127                         slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name);
128                         endsmbpwent(vp);
129                         return False;
130                 }
131         } else {
132                 /* the entry already existed */
133                 add_user = False;
134         }
135
136         /*
137          * We are root - just write the new password
138          * and the valid last change time.
139          */
140
141         if(disable_user) {
142                 smb_pwent->acct_ctrl |= ACB_DISABLED;
143         } else if (enable_user) {
144                 if(smb_pwent->smb_passwd == NULL) {
145                         smb_pwent->smb_passwd = new_p16;
146                         smb_pwent->smb_nt_passwd = new_nt_p16;
147                 }
148                 smb_pwent->acct_ctrl &= ~ACB_DISABLED;
149         } else if (set_no_password) {
150                 smb_pwent->acct_ctrl |= ACB_PWNOTREQ;
151                 /* This is needed to preserve ACB_PWNOTREQ in mod_smbfilepwd_entry */
152                 smb_pwent->smb_passwd = NULL;
153                 smb_pwent->smb_nt_passwd = NULL;
154         } else {
155                 /*
156                  * If we're dealing with setting a completely empty user account
157                  * ie. One with a password of 'XXXX', but not set disabled (like
158                  * an account created from scratch) then if the old password was
159                  * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
160                  * We remove that as we're giving this user their first password
161                  * and the decision hasn't really been made to disable them (ie.
162                  * don't create them disabled). JRA.
163                  */
164                 if((smb_pwent->smb_passwd == NULL) && (smb_pwent->acct_ctrl & ACB_DISABLED))
165                         smb_pwent->acct_ctrl &= ~ACB_DISABLED;
166                 smb_pwent->acct_ctrl &= ~ACB_PWNOTREQ;
167                 smb_pwent->smb_passwd = new_p16;
168                 smb_pwent->smb_nt_passwd = new_nt_p16;
169         }
170         
171         if(mod_smbpwd_entry(smb_pwent,True) == False) {
172                 slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n",
173                         pwd->pw_name);
174                 endsmbpwent(vp);
175                 return False;
176         }
177
178         endsmbpwent(vp);
179
180         return True;
181 }