Removed unneeded extern.
[jra/samba/.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 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
29    form DOMAIN/user into a domain and a user */
30
31 static void parse_domain_user(char *domuser, fstring domain, fstring user)
32 {
33         char *p;
34         char *sep = lp_winbind_separator();
35         if (!sep) sep = "\\";
36         p = strchr(domuser,*sep);
37         if (!p) p = strchr(domuser,'\\');
38         if (!p) {
39                 fstrcpy(domain,"");
40                 fstrcpy(user, domuser);
41                 return;
42         }
43         
44         fstrcpy(user, p+1);
45         fstrcpy(domain, domuser);
46         domain[PTR_DIFF(p, domuser)] = 0;
47         strupper(domain);
48 }
49
50 /* Return a password structure from a username.  Specify whether cached data 
51    can be returned. */
52
53 enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) 
54 {
55         NTSTATUS result;
56         fstring name_domain, name_user, auth_dc;
57         int passlen;
58         unsigned char trust_passwd[16];
59         time_t last_change_time;
60
61         auth_usersupplied_info *user_info;
62         auth_serversupplied_info *server_info;
63
64         DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
65                   state->request.data.auth.user));
66
67         /* Parse domain and username */
68
69         parse_domain_user(state->request.data.auth.user, name_domain, 
70                           name_user);
71
72         /* don't allow the null domain */
73
74         if (strcmp(name_domain,"") == 0) 
75                 return WINBINDD_ERROR;
76
77         passlen = strlen(state->request.data.auth.pass);
78                 
79         if (state->request.data.auth.pass[0]) {
80                 make_user_info_for_winbind(&user_info, 
81                                            name_user, name_domain,
82                                            state->request.data.auth.pass);
83         } else {
84                 return WINBINDD_ERROR;
85         }
86         
87         /*
88          * Get the machine account password for our primary domain
89          */
90
91         if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
92         {
93                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup()));
94                 return WINBINDD_ERROR;
95         }
96
97         if (!cm_get_dc_name(lp_workgroup(), auth_dc)) {
98                 DEBUG(3, ("Could not find dc for workgroup %s\n",
99                           lp_workgroup()));
100                 return WINBINDD_ERROR;
101         }
102
103         /* So domain_client_validate() actually opens a new connection
104            for each authentication performed.  This can theoretically
105            be optimised to use an already open IPC$ connection. */
106
107         result = domain_client_validate(user_info, &server_info,
108                                         auth_dc, trust_passwd, 
109                                         last_change_time);
110
111         free_server_info(&server_info); /* No info needed */
112
113         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
114 }
115
116 /* Challenge Response Authentication Protocol */
117
118 enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) 
119 {
120         NTSTATUS result;
121         fstring name_domain, name_user, auth_dc;
122         unsigned char trust_passwd[16];
123         time_t last_change_time;
124         auth_usersupplied_info *user_info;
125         auth_serversupplied_info *server_info;
126
127         DEBUG(3, ("[%5d]: pam auth crap %s\n", state->pid,
128                   state->request.data.auth_crap.user));
129
130         /* Parse domain and username */
131
132         parse_domain_user(state->request.data.auth_crap.user, name_domain, 
133                           name_user);
134
135         make_user_info_winbind_crap(&user_info, name_user, 
136                                     name_domain, state->request.data.auth_crap.chal,
137                                     (uchar *)state->request.data.auth_crap.lm_resp, 24,
138                                     (uchar *)state->request.data.auth_crap.nt_resp, 24);
139         
140         /*
141          * Get the machine account password for our primary domain
142          */
143
144         if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
145         {
146                 DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup()));
147                 return WINBINDD_ERROR;
148         }
149
150         if (!cm_get_dc_name(lp_workgroup(), auth_dc)) {
151                 DEBUG(3, ("Could not find dc for workgroup %s\n",
152                           lp_workgroup()));
153                 return WINBINDD_ERROR;
154         }
155
156         /* So domain_client_validate() actually opens a new connection
157            for each authentication performed.  This can theoretically
158            be optimised to use an already open IPC$ connection. */
159
160         result = domain_client_validate(user_info, &server_info,
161                                         auth_dc, trust_passwd,
162                                         last_change_time);
163
164         free_server_info(&server_info); /* No info needed */        
165
166         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
167 }
168
169 /* Change a user password */
170
171 enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
172 {
173     char *oldpass, *newpass;
174     fstring domain, user;
175     uchar nt_oldhash[16];
176     uchar lm_oldhash[16];
177
178     DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
179               state->request.data.chauthtok.user));
180
181     /* Setup crap */
182
183     if (state == NULL) return WINBINDD_ERROR;
184
185     parse_domain_user(state->request.data.chauthtok.user, domain, user);
186
187     oldpass = state->request.data.chauthtok.oldpass;
188     newpass = state->request.data.chauthtok.newpass;
189
190     nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash);
191
192     /* Change password */
193
194 #if 0
195
196     /* XXX */
197
198     if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user,
199                                lm_oldhash, nt_oldhash, newpass)) {
200         DEBUG(0, ("password change failed for user %s/%s\n", domain, user));
201         return WINBINDD_ERROR;
202     }
203 #endif
204     
205     return WINBINDD_OK;
206 }