Added copyright for me and AB.
[ira/wip.git] / source3 / nsswitch / winbindd_pam.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4
5    Winbind daemon - pam auuth funcions
6
7    Copyright (C) Andrew Tridgell 2000
8    Copyright (C) Tim Potter 2001
9    Copyright (C) Andrew Bartlett 2001
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "winbindd.h"
27
28 extern pstring global_myname;
29
30 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
31    form DOMAIN/user into a domain and a user */
32
33 static void parse_domain_user(char *domuser, fstring domain, fstring user)
34 {
35         char *p;
36         char *sep = lp_winbind_separator();
37         if (!sep) sep = "\\";
38         p = strchr(domuser,*sep);
39         if (!p) p = strchr(domuser,'\\');
40         if (!p) {
41                 fstrcpy(domain,"");
42                 fstrcpy(user, domuser);
43                 return;
44         }
45         
46         fstrcpy(user, p+1);
47         fstrcpy(domain, domuser);
48         domain[PTR_DIFF(p, domuser)] = 0;
49         strupper(domain);
50 }
51
52 /* Return a password structure from a username.  Specify whether cached data 
53    can be returned. */
54
55 enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) 
56 {
57         BOOL result;
58         fstring name_domain, name_user;
59         int passlen;
60         unsigned char trust_passwd[16];
61         time_t last_change_time;
62
63         unsigned char local_lm_response[24];
64         unsigned char local_nt_response[24];
65
66         auth_usersupplied_info user_info;
67         auth_serversupplied_info server_info;
68         AUTH_STR theirdomain, smb_username, wksta_name;
69
70         DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
71                   state->request.data.auth.user));
72
73         /* Parse domain and username */
74
75         parse_domain_user(state->request.data.auth.user, name_domain, 
76                           name_user);
77
78         /* don't allow the null domain */
79
80         if (strcmp(name_domain,"") == 0) 
81                 return WINBINDD_ERROR;
82
83         passlen = strlen(state->request.data.auth.pass);
84                 
85         ZERO_STRUCT(user_info);
86         ZERO_STRUCT(theirdomain);
87         ZERO_STRUCT(smb_username);
88         ZERO_STRUCT(wksta_name);
89         
90         theirdomain.str = name_domain;
91         theirdomain.len = strlen(theirdomain.str);
92
93         user_info.requested_domain = theirdomain;
94         user_info.domain = theirdomain;
95         
96         user_info.smb_username.str = name_user;
97         user_info.smb_username.len = strlen(name_user);
98
99         user_info.requested_username.str = name_user;
100         user_info.requested_username.len = strlen(name_user);
101
102         user_info.wksta_name.str = global_myname;
103         user_info.wksta_name.len = strlen(user_info.wksta_name.str);
104
105         user_info.wksta_name = wksta_name;
106
107         generate_random_buffer( user_info.chal, 8, False);
108
109         if (state->request.data.auth.pass[0]) {
110                 SMBencrypt((uchar *)state->request.data.auth.pass, user_info.chal, local_lm_response);
111                 user_info.lm_resp.buffer = (uint8 *)local_lm_response;
112                 user_info.lm_resp.len = 24;
113                 SMBNTencrypt((uchar *)state->request.data.auth.pass, user_info.chal, local_nt_response);
114                 user_info.nt_resp.buffer = (uint8 *)local_nt_response;
115                 user_info.nt_resp.len = 24;
116         } else {
117                 return WINBINDD_ERROR;
118         }
119         
120         /*
121          * Get the machine account password for our primary domain
122          */
123
124         if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
125         {
126                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup()));
127                 return WINBINDD_ERROR;
128         }
129
130         /* So domain_client_validate() actually opens a new connection
131            for each authentication performed.  This can theoretically
132            be optimised to use an already open IPC$ connection. */
133
134         result = (domain_client_validate(&user_info, &server_info,
135                                          server_state.controller, trust_passwd,
136                                          last_change_time) == NT_STATUS_NOPROBLEMO);
137
138         return result ? WINBINDD_OK : WINBINDD_ERROR;
139 }
140
141 /* Challenge Response Authentication Protocol */
142
143 enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) 
144 {
145         BOOL result;
146         fstring name_domain, name_user;
147         unsigned char trust_passwd[16];
148         time_t last_change_time;
149         auth_usersupplied_info user_info;
150         auth_serversupplied_info server_info;
151         AUTH_STR theirdomain, smb_username, wksta_name;
152
153         DEBUG(3, ("[%5d]: pam auth crap %s\n", state->pid,
154                   state->request.data.auth_crap.user));
155
156         /* Parse domain and username */
157
158         parse_domain_user(state->request.data.auth_crap.user, name_domain, 
159                           name_user);
160
161         ZERO_STRUCT(user_info);
162         ZERO_STRUCT(theirdomain);
163         ZERO_STRUCT(smb_username);
164         ZERO_STRUCT(wksta_name);
165         
166         theirdomain.str = name_domain;
167         theirdomain.len = strlen(theirdomain.str);
168
169         user_info.requested_domain = theirdomain;
170         user_info.domain = theirdomain;
171         
172         user_info.smb_username.str = name_user;
173         user_info.smb_username.len = strlen(name_user);
174
175         user_info.requested_username.str = name_user;
176         user_info.requested_username.len = strlen(name_user);
177
178         user_info.wksta_name.str = global_myname;
179         user_info.wksta_name.len = strlen(user_info.wksta_name.str);
180
181         user_info.wksta_name = wksta_name;
182
183         memcpy(user_info.chal, state->request.data.auth_crap.chal, 8);
184
185         user_info.lm_resp.buffer = state->request.data.auth_crap.lm_resp;
186         user_info.nt_resp.buffer = state->request.data.auth_crap.nt_resp;
187         
188         user_info.lm_resp.len = 24;
189         user_info.nt_resp.len = 24;
190
191         /*
192          * Get the machine account password for our primary domain
193          */
194
195         if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
196         {
197                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup()));
198                 return WINBINDD_ERROR;
199         }
200
201         /* So domain_client_validate() actually opens a new connection
202            for each authentication performed.  This can theoretically
203            be optimised to use an already open IPC$ connection. */
204
205         result = (domain_client_validate(&user_info, &server_info,
206                                          server_state.controller, trust_passwd,
207                                          last_change_time) == NT_STATUS_NOPROBLEMO);
208
209         return result ? WINBINDD_OK : WINBINDD_ERROR;
210 }
211
212 /* Change a user password */
213
214 enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
215 {
216     char *oldpass, *newpass;
217     fstring domain, user;
218     uchar nt_oldhash[16];
219     uchar lm_oldhash[16];
220
221     DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
222               state->request.data.chauthtok.user));
223
224     /* Setup crap */
225
226     if (state == NULL) return WINBINDD_ERROR;
227
228     parse_domain_user(state->request.data.chauthtok.user, domain, user);
229
230     oldpass = state->request.data.chauthtok.oldpass;
231     newpass = state->request.data.chauthtok.newpass;
232
233     nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash);
234
235     /* Change password */
236
237 #if 0
238
239     /* XXX */
240
241     if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user,
242                                lm_oldhash, nt_oldhash, newpass)) {
243         DEBUG(0, ("password change failed for user %s/%s\n", domain, user));
244         return WINBINDD_ERROR;
245     }
246 #endif
247     
248     return WINBINDD_OK;
249 }