Removed version number from file header.
[samba.git] / source3 / nsswitch / winbindd_pam.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - pam auth funcions
5
6    Copyright (C) Andrew Tridgell 2000
7    Copyright (C) Tim Potter 2001
8    Copyright (C) Andrew Bartlett 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 #include "winbindd.h"
26
27 /* Return a password structure from a username.  */
28
29 enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) 
30 {
31         NTSTATUS result;
32         fstring name_domain, name_user;
33         int passlen;
34         unsigned char trust_passwd[16];
35         time_t last_change_time;
36         uint32 smb_uid_low;
37         NET_USER_INFO_3 info3;
38         struct cli_state *cli = NULL;
39         uchar chal[8];
40         TALLOC_CTX *mem_ctx;
41         DATA_BLOB lm_resp;
42         DATA_BLOB nt_resp;
43
44         extern pstring global_myname;
45
46         DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
47                   state->request.data.auth.user));
48
49         if (!(mem_ctx = talloc_init_named("winbind pam auth for %s", state->request.data.auth.user))) {
50                 DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n"));
51                 return WINBINDD_ERROR;
52         }
53
54         /* Parse domain and username */
55         
56         if (!parse_domain_user(state->request.data.auth.user, name_domain, 
57                                name_user)) {
58                 DEBUG(5,("no domain seperator (%s) in username (%s) - failing auth\n", lp_winbind_separator(), state->request.data.auth.user));
59                 talloc_destroy(mem_ctx);
60                 return WINBINDD_ERROR;
61         }
62
63         passlen = strlen(state->request.data.auth.pass);
64                 
65         if (!*state->request.data.auth.pass) {
66                 return WINBINDD_ERROR;
67                 talloc_destroy(mem_ctx);
68         } else {
69                 unsigned char local_lm_response[24];
70                 unsigned char local_nt_response[24];
71                 
72                 generate_random_buffer(chal, 8, False);
73                 SMBencrypt( (const uchar *)state->request.data.auth.pass, chal, local_lm_response);
74                 
75                 SMBNTencrypt((const uchar *)state->request.data.auth.pass, chal, local_nt_response);
76
77                 lm_resp = data_blob_talloc(mem_ctx, local_lm_response, sizeof(local_lm_response));
78                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response, sizeof(local_nt_response));
79         }
80         
81         /*
82          * Get the machine account password for our primary domain
83          */
84
85         if (!secrets_fetch_trust_account_password(
86                 lp_workgroup(), trust_passwd, &last_change_time)) {
87                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
88                           "password for domain %s\n", lp_workgroup()));
89                 talloc_destroy(mem_ctx);
90                 return WINBINDD_ERROR;
91         }
92
93         /* We really don't care what LUID we give the user. */
94
95         generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
96
97         ZERO_STRUCT(info3);
98
99         result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
100
101         if (!NT_STATUS_IS_OK(result)) {
102                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
103                 goto done;
104         }
105
106         result = cli_netlogon_sam_network_logon(cli, mem_ctx,
107                                                 name_user, name_domain, 
108                                                 global_myname, chal, 
109                                                 lm_resp, nt_resp, 
110                                                 &info3);
111         
112         uni_group_cache_store_netlogon(mem_ctx, &info3);
113 done:
114
115         if (cli) 
116                 cli_shutdown(cli);
117
118         talloc_destroy(mem_ctx);
119         
120         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
121 }
122         
123 /* Challenge Response Authentication Protocol */
124
125 enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) 
126 {
127         NTSTATUS result;
128         unsigned char trust_passwd[16];
129         time_t last_change_time;
130         NET_USER_INFO_3 info3;
131         struct cli_state *cli = NULL;
132         TALLOC_CTX *mem_ctx;
133         const char *domain = NULL;
134
135         DATA_BLOB lm_resp, nt_resp;
136
137         extern pstring global_myname;
138
139         DEBUG(3, ("[%5d]: pam auth crap domain: %s user: %s\n", state->pid,
140                   state->request.data.auth_crap.user, state->request.data.auth_crap.user));
141
142         if (!(mem_ctx = talloc_init_named("winbind pam auth crap for %s", state->request.data.auth.user))) {
143                 DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
144                 return WINBINDD_ERROR;
145         }
146
147         if (*state->request.data.auth_crap.domain) {
148                 domain = talloc_strdup(mem_ctx, state->request.data.auth_crap.domain);
149         } else if (lp_winbind_use_default_domain()) {
150                 domain = talloc_strdup(mem_ctx, lp_workgroup());
151         } else {
152                 DEBUG(5,("no domain specified with username (%s) - failing auth\n", state->request.data.auth.user));
153                 talloc_destroy(mem_ctx);
154                 return WINBINDD_ERROR;
155         }
156
157         if (!domain) {
158                 DEBUG(0,("winbindd_pam_auth_crap: talloc_strdup failed!\n"));
159                 talloc_destroy(mem_ctx);
160                 return WINBINDD_ERROR;
161         }
162
163         lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
164         nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
165         
166         /*
167          * Get the machine account password for our primary domain
168          */
169
170         if (!secrets_fetch_trust_account_password(
171                 lp_workgroup(), trust_passwd, &last_change_time)) {
172                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
173                           "password for domain %s\n", lp_workgroup()));
174                 talloc_destroy(mem_ctx);
175                 return WINBINDD_ERROR;
176         }
177
178         ZERO_STRUCT(info3);
179
180         result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
181
182         if (!NT_STATUS_IS_OK(result)) {
183                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
184                 goto done;
185         }
186
187         result = cli_netlogon_sam_network_logon(cli, mem_ctx,
188                                                 state->request.data.auth_crap.user, domain,
189                                                 global_myname, state->request.data.auth_crap.chal, 
190                                                 lm_resp, nt_resp, 
191                                                 &info3);
192         
193         uni_group_cache_store_netlogon(mem_ctx, &info3);
194 done:
195         talloc_destroy(mem_ctx);
196
197         if (cli)
198                 cli_shutdown(cli);
199
200         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
201 }
202
203 /* Change a user password */
204
205 enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
206 {
207         char *oldpass, *newpass;
208         fstring domain, user;
209         uchar nt_oldhash[16];
210         uchar lm_oldhash[16];
211         CLI_POLICY_HND *hnd;
212
213         DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
214                 state->request.data.chauthtok.user));
215
216         /* Setup crap */
217
218         if (state == NULL)
219                 return WINBINDD_ERROR;
220
221         if (!parse_domain_user(state->request.data.chauthtok.user, domain, 
222                                user))
223                 return WINBINDD_ERROR;
224
225         /* Change password */
226
227         oldpass = state->request.data.chauthtok.oldpass;
228         newpass = state->request.data.chauthtok.newpass;
229
230         /* Get sam handle */
231
232         if (!(hnd = cm_get_sam_handle(domain)))
233                 return WINBINDD_ERROR;
234
235         if (!cli_oem_change_password(hnd->cli, user, newpass, oldpass)) {
236                 DEBUG(0, ("password change failed for user %s/%s\n", domain, 
237                           user));
238                 return WINBINDD_ERROR;
239         }
240     
241         return WINBINDD_OK;
242 }