libwbclient: unimplement wbcSetUidHwm()
[amitay/samba.git] / nsswitch / libwbclient / wbc_pam_async.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) 2009 Kai Blin  <kai@samba.org>
7
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 3 of the License, or (at your option) any later version.
12
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Library General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* Required Headers */
23
24 #include "replace.h"
25 #include "libwbclient.h"
26 #include "../winbind_client.h"
27 #include "wbc_async.h"
28
29 /* FIXME: Currently this is still a copy of the same function from wbc_pam.c */
30 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
31                                    const struct winbindd_response *resp,
32                                    struct wbcAuthUserInfo **_i)
33 {
34         wbcErr wbc_status = WBC_ERR_SUCCESS;
35         struct wbcAuthUserInfo *i;
36         struct wbcDomainSid domain_sid;
37         char *p;
38         uint32_t sn = 0;
39         uint32_t j;
40
41         i = talloc(mem_ctx, struct wbcAuthUserInfo);
42         BAIL_ON_PTR_ERROR(i, wbc_status);
43
44         i->user_flags   = resp->data.auth.info3.user_flgs;
45
46         i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
47         BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
48         i->user_principal= NULL;
49         i->full_name    = talloc_strdup(i, resp->data.auth.info3.full_name);
50         BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
51         i->domain_name  = talloc_strdup(i, resp->data.auth.info3.logon_dom);
52         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
53         i->dns_domain_name= NULL;
54
55         i->acct_flags   = resp->data.auth.info3.acct_flags;
56         memcpy(i->user_session_key,
57                resp->data.auth.user_session_key,
58                sizeof(i->user_session_key));
59         memcpy(i->lm_session_key,
60                resp->data.auth.first_8_lm_hash,
61                sizeof(i->lm_session_key));
62
63         i->logon_count          = resp->data.auth.info3.logon_count;
64         i->bad_password_count   = resp->data.auth.info3.bad_pw_count;
65
66         i->logon_time           = resp->data.auth.info3.logon_time;
67         i->logoff_time          = resp->data.auth.info3.logoff_time;
68         i->kickoff_time         = resp->data.auth.info3.kickoff_time;
69         i->pass_last_set_time   = resp->data.auth.info3.pass_last_set_time;
70         i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
71         i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
72
73         i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
74         BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
75         i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
76         BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
77         i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
78         BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
79         i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
80         BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
81         i->home_drive   = talloc_strdup(i, resp->data.auth.info3.dir_drive);
82         BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
83
84         i->num_sids     = 2;
85         i->num_sids     += resp->data.auth.info3.num_groups;
86         i->num_sids     += resp->data.auth.info3.num_other_sids;
87
88         i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
89         BAIL_ON_PTR_ERROR(i->sids, wbc_status);
90
91         wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
92                                     &domain_sid);
93         BAIL_ON_WBC_ERROR(wbc_status);
94
95 #define _SID_COMPOSE(s, d, r, a) { \
96         (s).sid = d; \
97         if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \
98                 (s).sid.sub_auths[(s).sid.num_auths++] = r; \
99         } else { \
100                 wbc_status = WBC_ERR_INVALID_SID; \
101                 BAIL_ON_WBC_ERROR(wbc_status); \
102         } \
103         (s).attributes = a; \
104 } while (0)
105
106         sn = 0;
107         _SID_COMPOSE(i->sids[sn], domain_sid,
108                      resp->data.auth.info3.user_rid,
109                      0);
110         sn++;
111         _SID_COMPOSE(i->sids[sn], domain_sid,
112                      resp->data.auth.info3.group_rid,
113                      0);
114         sn++;
115
116         p = (char *)resp->extra_data.data;
117         if (!p) {
118                 wbc_status = WBC_ERR_INVALID_RESPONSE;
119                 BAIL_ON_WBC_ERROR(wbc_status);
120         }
121
122         for (j=0; j < resp->data.auth.info3.num_groups; j++) {
123                 uint32_t rid;
124                 uint32_t attrs;
125                 int ret;
126                 char *s = p;
127                 char *e = strchr(p, '\n');
128                 if (!e) {
129                         wbc_status = WBC_ERR_INVALID_RESPONSE;
130                         BAIL_ON_WBC_ERROR(wbc_status);
131                 }
132                 e[0] = '\0';
133                 p = &e[1];
134
135                 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
136                 if (ret != 2) {
137                         wbc_status = WBC_ERR_INVALID_RESPONSE;
138                         BAIL_ON_WBC_ERROR(wbc_status);
139                 }
140
141                 _SID_COMPOSE(i->sids[sn], domain_sid,
142                              rid, attrs);
143                 sn++;
144         }
145
146         for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
147                 uint32_t attrs;
148                 int ret;
149                 char *s = p;
150                 char *a;
151                 char *e = strchr(p, '\n');
152                 if (!e) {
153                         wbc_status = WBC_ERR_INVALID_RESPONSE;
154                         BAIL_ON_WBC_ERROR(wbc_status);
155                 }
156                 e[0] = '\0';
157                 p = &e[1];
158
159                 e = strchr(s, ':');
160                 if (!e) {
161                         wbc_status = WBC_ERR_INVALID_RESPONSE;
162                         BAIL_ON_WBC_ERROR(wbc_status);
163                 }
164                 e[0] = '\0';
165                 a = &e[1];
166
167                 ret = sscanf(a, "0x%08X",
168                              &attrs);
169                 if (ret != 1) {
170                         wbc_status = WBC_ERR_INVALID_RESPONSE;
171                         BAIL_ON_WBC_ERROR(wbc_status);
172                 }
173
174                 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
175                 BAIL_ON_WBC_ERROR(wbc_status);
176
177                 i->sids[sn].attributes = attrs;
178                 sn++;
179         }
180
181         i->num_sids = sn;
182
183         *_i = i;
184         i = NULL;
185 done:
186         talloc_free(i);
187         return wbc_status;
188 }
189
190 /* FIXME: Currently this is still a copy of the same function from wbc_pam.c */
191 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
192                                     struct wbcAuthErrorInfo **_e)
193 {
194         wbcErr wbc_status = WBC_ERR_SUCCESS;
195         struct wbcAuthErrorInfo *e;
196
197         e = talloc(NULL, struct wbcAuthErrorInfo);
198         BAIL_ON_PTR_ERROR(e, wbc_status);
199
200         e->nt_status = resp->data.auth.nt_status;
201         e->pam_error = resp->data.auth.pam_error;
202         e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
203         BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
204
205         e->display_string = talloc_strdup(e, resp->data.auth.error_string);
206         BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
207
208         *_e = e;
209         e = NULL;
210
211 done:
212         talloc_free(e);
213         return wbc_status;
214 }
215
216 struct wbc_authenticate_user_ex_state {
217         struct winbindd_request req;
218         struct tevent_context *ev;
219         struct wb_context *wb_ctx;
220         const struct wbcAuthUserParams *params;
221         struct wbcAuthUserInfo *info;
222         struct wbcAuthErrorInfo *error;
223 };
224
225 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq);
226 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq);
227
228 struct tevent_req *wbcAuthenticateUserEx_send(TALLOC_CTX *mem_ctx,
229                                         struct tevent_context *ev,
230                                         struct wb_context *wb_ctx,
231                                         const struct wbcAuthUserParams *params)
232 {
233         struct tevent_req *req, *subreq;
234         struct wbc_authenticate_user_ex_state *state;
235
236         req = tevent_req_create(mem_ctx, &state,
237                                 struct wbc_authenticate_user_ex_state);
238         if (req == NULL) {
239                 return NULL;
240         }
241
242         state->ev = ev;
243         state->wb_ctx = wb_ctx;
244         state->params = params;
245
246         if (!params) {
247                 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
248                 return tevent_req_post(req, ev);
249         }
250
251         if (!params->account_name) {
252                 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
253                 return tevent_req_post(req, ev);
254         }
255
256         ZERO_STRUCT(state->req);
257
258         if (params->flags) {
259                 state->req.flags = params->flags;
260         }
261
262         switch (params->level) {
263         case WBC_AUTH_USER_LEVEL_PLAIN:
264                 state->req.cmd = WINBINDD_PAM_AUTH;
265                 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
266                                     WBFLAG_PAM_USER_SESSION_KEY |
267                                     WBFLAG_PAM_LMKEY;
268
269                 if (!params->password.plaintext) {
270                         tevent_req_error(req, WBC_ERR_INVALID_PARAM);
271                         return tevent_req_post(req, ev);
272                 }
273
274                 strncpy(state->req.data.auth.pass,
275                         params->password.plaintext,
276                         sizeof(state->req.data.auth.pass)-1);
277
278                 if (params->domain_name && params->domain_name[0]) {
279                         /* We need to get the winbind separator :-( */
280                         subreq = wbcInfo_send(state, ev, wb_ctx);
281                         if (tevent_req_nomem(subreq, req)) {
282                                 return tevent_req_post(req, ev);
283                         }
284
285                         tevent_req_set_callback(subreq,
286                                                 wbcAuthenticateUserEx_got_info,
287                                                 req);
288                         return req;
289                 } else {
290                         strncpy(state->req.data.auth.user,
291                                 params->account_name,
292                                 sizeof(state->req.data.auth.user)-1);
293                 }
294
295                 break;
296
297         case WBC_AUTH_USER_LEVEL_HASH:
298                 tevent_req_error(req, WBC_ERR_NOT_IMPLEMENTED);
299                 return tevent_req_post(req, ev);
300                 /* Make some static code checkers happy */
301                 break;
302
303         case WBC_AUTH_USER_LEVEL_RESPONSE:
304                 state->req.cmd = WINBINDD_PAM_AUTH_CRAP;
305                 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
306                                     WBFLAG_PAM_USER_SESSION_KEY |
307                                     WBFLAG_PAM_LMKEY;
308
309                 if (params->password.response.lm_length &&
310                     !params->password.response.lm_data) {
311                         tevent_req_error(req, WBC_ERR_INVALID_PARAM);
312                         return tevent_req_post(req, ev);
313                 }
314                 if (params->password.response.lm_length == 0 &&
315                     params->password.response.lm_data) {
316                         tevent_req_error(req, WBC_ERR_INVALID_PARAM);
317                         return tevent_req_post(req, ev);
318                 }
319
320                 if (params->password.response.nt_length &&
321                     !params->password.response.nt_data) {
322                         tevent_req_error(req, WBC_ERR_INVALID_PARAM);
323                         return tevent_req_post(req, ev);
324                 }
325                 if (params->password.response.nt_length == 0&&
326                     params->password.response.nt_data) {
327                         tevent_req_error(req, WBC_ERR_INVALID_PARAM);
328                         return tevent_req_post(req, ev);
329                 }
330
331                 strncpy(state->req.data.auth_crap.user,
332                         params->account_name,
333                         sizeof(state->req.data.auth_crap.user)-1);
334                 if (params->domain_name) {
335                         strncpy(state->req.data.auth_crap.domain,
336                                 params->domain_name,
337                                 sizeof(state->req.data.auth_crap.domain)-1);
338                 }
339                 if (params->workstation_name) {
340                         strncpy(state->req.data.auth_crap.workstation,
341                                 params->workstation_name,
342                                 sizeof(state->req.data.auth_crap.workstation)-1);
343                 }
344
345                 state->req.data.auth_crap.logon_parameters =
346                                 params->parameter_control;
347
348                 memcpy(state->req.data.auth_crap.chal,
349                        params->password.response.challenge,
350                        sizeof(state->req.data.auth_crap.chal));
351
352                 state->req.data.auth_crap.lm_resp_len =
353                                 MIN(params->password.response.lm_length,
354                                     sizeof(state->req.data.auth_crap.lm_resp));
355                 state->req.data.auth_crap.nt_resp_len =
356                                 MIN(params->password.response.nt_length,
357                                     sizeof(state->req.data.auth_crap.nt_resp));
358                 if (params->password.response.lm_data) {
359                         memcpy(state->req.data.auth_crap.lm_resp,
360                                params->password.response.lm_data,
361                                state->req.data.auth_crap.lm_resp_len);
362                 }
363                 if (params->password.response.nt_data) {
364                         memcpy(state->req.data.auth_crap.nt_resp,
365                                params->password.response.nt_data,
366                                state->req.data.auth_crap.nt_resp_len);
367                 }
368                 break;
369         default:
370                 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
371                 return tevent_req_post(req, ev);
372                 break;
373         }
374
375         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
376         if (tevent_req_nomem(subreq, req)) {
377                 return tevent_req_post(req, ev);
378         }
379
380         tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
381         return req;
382 }
383
384 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq)
385 {
386         struct tevent_req *req = tevent_req_callback_data(
387                         subreq, struct tevent_req);
388         struct wbc_authenticate_user_ex_state *state = tevent_req_data(
389                         req, struct wbc_authenticate_user_ex_state);
390         char *version_string;
391         char separator;
392         wbcErr wbc_status;
393
394         wbc_status = wbcInfo_recv(subreq, state, &separator, &version_string);
395         TALLOC_FREE(subreq);
396         if (!WBC_ERROR_IS_OK(wbc_status)) {
397                 tevent_req_error(req, wbc_status);
398                 return;
399         }
400
401         snprintf(state->req.data.auth.user,
402                  sizeof(state->req.data.auth.user)-1,
403                  "%s%c%s",
404                  state->params->domain_name,
405                  separator,
406                  state->params->account_name);
407
408         subreq = wb_trans_send(state, state->ev, state->wb_ctx, false,
409                                &state->req);
410         if (tevent_req_nomem(subreq, req)) {
411                 return;
412         }
413
414         tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
415         return;
416 }
417
418 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq)
419 {
420         struct tevent_req *req = tevent_req_callback_data(
421                         subreq, struct tevent_req);
422         struct wbc_authenticate_user_ex_state *state = tevent_req_data(
423                         req, struct wbc_authenticate_user_ex_state);
424         struct winbindd_response *resp;
425         wbcErr wbc_status;
426
427         ZERO_STRUCT(resp);
428
429         wbc_status = wb_trans_recv(subreq, state, &resp);
430         TALLOC_FREE(subreq);
431         if (!WBC_ERROR_IS_OK(wbc_status)) {
432                 tevent_req_error(req, wbc_status);
433                 goto done;
434         }
435
436         if (resp->data.auth.nt_status != 0) {
437                 wbc_status = wbc_create_error_info(resp, &state->error);
438                 if (!WBC_ERROR_IS_OK(wbc_status)) {
439                         tevent_req_error(req, wbc_status);
440                         goto done;
441                 }
442
443                 tevent_req_error(req, WBC_ERR_AUTH_ERROR);
444                 goto done;
445         }
446
447         wbc_status = wbc_create_auth_info(state, resp, &state->info);
448         if (!WBC_ERROR_IS_OK(wbc_status)) {
449                 tevent_req_error(req, wbc_status);
450                 goto done;
451         }
452
453 done:
454         TALLOC_FREE(resp);
455 }
456
457 wbcErr wbcAuthenticateUserEx_recv(struct tevent_req *req,
458                                   TALLOC_CTX *mem_ctx,
459                                   struct wbcAuthUserInfo **info,
460                                   struct wbcAuthErrorInfo **error)
461 {
462         struct wbc_authenticate_user_ex_state *state = tevent_req_data(
463                         req, struct wbc_authenticate_user_ex_state);
464         wbcErr wbc_status;
465
466         if (error) {
467                 *error = NULL;
468         }
469
470         if (tevent_req_is_wbcerr(req, &wbc_status)) {
471                 tevent_req_received(req);
472                 if (error) {
473                         *error = talloc_steal(mem_ctx, state->error);
474                 }
475                 return wbc_status;
476         }
477
478         if (info) {
479                 *info = talloc_steal(mem_ctx, state->info);
480         }
481
482         tevent_req_received(req);
483         return wbc_status;
484 }