cb2d5a0f4c4ab913b339bc7ac58ffff5c9ef2d42
[nivanova/samba-autobuild/.git] / nsswitch / libwbclient / wbc_pam.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) Gerald (Jerry) Carter 2007
7    Copyright (C) Guenther Deschner 2008
8    Copyright (C) Volker Lendecke 2009
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library 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 GNU
18    Library General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /* Required Headers */
25
26 #include "replace.h"
27 #include "libwbclient.h"
28 #include "../winbind_client.h"
29
30 /* Authenticate a username/password pair */
31 wbcErr wbcCtxAuthenticateUser(struct wbcContext *ctx,
32                               const char *username, const char *password)
33 {
34         wbcErr wbc_status = WBC_ERR_SUCCESS;
35         struct wbcAuthUserParams params;
36
37         ZERO_STRUCT(params);
38
39         params.account_name             = username;
40         params.level                    = WBC_AUTH_USER_LEVEL_PLAIN;
41         params.password.plaintext       = password;
42
43         wbc_status = wbcCtxAuthenticateUserEx(ctx, &params, NULL, NULL);
44         BAIL_ON_WBC_ERROR(wbc_status);
45
46 done:
47         return wbc_status;
48 }
49
50 wbcErr wbcAuthenticateUser(const char *username, const char *password)
51 {
52         return wbcCtxAuthenticateUser(NULL, username, password);
53 }
54
55 static bool sid_attr_compose(struct wbcSidWithAttr *s,
56                              const struct wbcDomainSid *d,
57                              uint32_t rid, uint32_t attr)
58 {
59         if (d->num_auths >= WBC_MAXSUBAUTHS) {
60                 return false;
61         }
62         s->sid = *d;
63         s->sid.sub_auths[s->sid.num_auths++] = rid;
64         s->attributes = attr;
65         return true;
66 }
67
68 static void wbcAuthUserInfoDestructor(void *ptr)
69 {
70         struct wbcAuthUserInfo *i = (struct wbcAuthUserInfo *)ptr;
71         free(i->account_name);
72         free(i->user_principal);
73         free(i->full_name);
74         free(i->domain_name);
75         free(i->dns_domain_name);
76         free(i->logon_server);
77         free(i->logon_script);
78         free(i->profile_path);
79         free(i->home_directory);
80         free(i->home_drive);
81         free(i->sids);
82 }
83
84 static wbcErr wbc_create_auth_info(const struct winbindd_response *resp,
85                                    struct wbcAuthUserInfo **_i)
86 {
87         wbcErr wbc_status = WBC_ERR_SUCCESS;
88         struct wbcAuthUserInfo *i;
89         struct wbcDomainSid domain_sid;
90         char *p;
91         uint32_t sn = 0;
92         uint32_t j;
93
94         i = (struct wbcAuthUserInfo *)wbcAllocateMemory(
95                 1, sizeof(struct wbcAuthUserInfo),
96                 wbcAuthUserInfoDestructor);
97         BAIL_ON_PTR_ERROR(i, wbc_status);
98
99         i->user_flags   = resp->data.auth.info3.user_flgs;
100
101         i->account_name = strdup(resp->data.auth.info3.user_name);
102         BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
103         i->user_principal= NULL;
104         i->full_name    = strdup(resp->data.auth.info3.full_name);
105         BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
106         i->domain_name  = strdup(resp->data.auth.info3.logon_dom);
107         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
108         i->dns_domain_name= NULL;
109
110         i->acct_flags   = resp->data.auth.info3.acct_flags;
111         memcpy(i->user_session_key,
112                resp->data.auth.user_session_key,
113                sizeof(i->user_session_key));
114         memcpy(i->lm_session_key,
115                resp->data.auth.first_8_lm_hash,
116                sizeof(i->lm_session_key));
117
118         i->logon_count          = resp->data.auth.info3.logon_count;
119         i->bad_password_count   = resp->data.auth.info3.bad_pw_count;
120
121         i->logon_time           = resp->data.auth.info3.logon_time;
122         i->logoff_time          = resp->data.auth.info3.logoff_time;
123         i->kickoff_time         = resp->data.auth.info3.kickoff_time;
124         i->pass_last_set_time   = resp->data.auth.info3.pass_last_set_time;
125         i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
126         i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
127
128         i->logon_server = strdup(resp->data.auth.info3.logon_srv);
129         BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
130         i->logon_script = strdup(resp->data.auth.info3.logon_script);
131         BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
132         i->profile_path = strdup(resp->data.auth.info3.profile_path);
133         BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
134         i->home_directory= strdup(resp->data.auth.info3.home_dir);
135         BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
136         i->home_drive   = strdup(resp->data.auth.info3.dir_drive);
137         BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
138
139         i->num_sids     = 2;
140         i->num_sids     += resp->data.auth.info3.num_groups;
141         i->num_sids     += resp->data.auth.info3.num_other_sids;
142
143         i->sids = (struct wbcSidWithAttr *)calloc(
144                 sizeof(struct wbcSidWithAttr), i->num_sids);
145         BAIL_ON_PTR_ERROR(i->sids, wbc_status);
146
147         wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
148                                     &domain_sid);
149         BAIL_ON_WBC_ERROR(wbc_status);
150
151         sn = 0;
152         if (!sid_attr_compose(&i->sids[sn], &domain_sid,
153                               resp->data.auth.info3.user_rid, 0)) {
154                 wbc_status = WBC_ERR_INVALID_SID;
155                 goto done;
156         }
157         sn++;
158         if (!sid_attr_compose(&i->sids[sn], &domain_sid,
159                               resp->data.auth.info3.group_rid, 0)) {
160                 wbc_status = WBC_ERR_INVALID_SID;
161                 goto done;
162         }
163         sn++;
164
165         p = (char *)resp->extra_data.data;
166         if (!p) {
167                 wbc_status = WBC_ERR_INVALID_RESPONSE;
168                 BAIL_ON_WBC_ERROR(wbc_status);
169         }
170
171         for (j=0; j < resp->data.auth.info3.num_groups; j++) {
172                 uint32_t rid;
173                 uint32_t attrs;
174                 int ret;
175                 char *s = p;
176                 char *e = strchr(p, '\n');
177                 if (!e) {
178                         wbc_status = WBC_ERR_INVALID_RESPONSE;
179                         BAIL_ON_WBC_ERROR(wbc_status);
180                 }
181                 e[0] = '\0';
182                 p = &e[1];
183
184                 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
185                 if (ret != 2) {
186                         wbc_status = WBC_ERR_INVALID_RESPONSE;
187                         BAIL_ON_WBC_ERROR(wbc_status);
188                 }
189
190                 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
191                                       rid, attrs)) {
192                         wbc_status = WBC_ERR_INVALID_SID;
193                         goto done;
194                 }
195                 sn++;
196         }
197
198         for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
199                 uint32_t attrs;
200                 int ret;
201                 char *s = p;
202                 char *a;
203                 char *e = strchr(p, '\n');
204                 if (!e) {
205                         wbc_status = WBC_ERR_INVALID_RESPONSE;
206                         BAIL_ON_WBC_ERROR(wbc_status);
207                 }
208                 e[0] = '\0';
209                 p = &e[1];
210
211                 e = strchr(s, ':');
212                 if (!e) {
213                         wbc_status = WBC_ERR_INVALID_RESPONSE;
214                         BAIL_ON_WBC_ERROR(wbc_status);
215                 }
216                 e[0] = '\0';
217                 a = &e[1];
218
219                 ret = sscanf(a, "0x%08X",
220                              &attrs);
221                 if (ret != 1) {
222                         wbc_status = WBC_ERR_INVALID_RESPONSE;
223                         BAIL_ON_WBC_ERROR(wbc_status);
224                 }
225
226                 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
227                 BAIL_ON_WBC_ERROR(wbc_status);
228
229                 i->sids[sn].attributes = attrs;
230                 sn++;
231         }
232
233         i->num_sids = sn;
234
235         *_i = i;
236         i = NULL;
237 done:
238         wbcFreeMemory(i);
239         return wbc_status;
240 }
241
242 static void wbcAuthErrorInfoDestructor(void *ptr)
243 {
244         struct wbcAuthErrorInfo *e = (struct wbcAuthErrorInfo *)ptr;
245         free(e->nt_string);
246         free(e->display_string);
247 }
248
249 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
250                                     struct wbcAuthErrorInfo **_e)
251 {
252         wbcErr wbc_status = WBC_ERR_SUCCESS;
253         struct wbcAuthErrorInfo *e;
254
255         e = (struct wbcAuthErrorInfo *)wbcAllocateMemory(
256                 1, sizeof(struct wbcAuthErrorInfo),
257                 wbcAuthErrorInfoDestructor);
258         BAIL_ON_PTR_ERROR(e, wbc_status);
259
260         e->nt_status = resp->data.auth.nt_status;
261         e->pam_error = resp->data.auth.pam_error;
262         e->authoritative = resp->data.auth.authoritative;
263         e->nt_string = strdup(resp->data.auth.nt_status_string);
264         BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
265
266         e->display_string = strdup(resp->data.auth.error_string);
267         BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
268
269         *_e = e;
270         e = NULL;
271
272 done:
273         wbcFreeMemory(e);
274         return wbc_status;
275 }
276
277 static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
278                                               struct wbcUserPasswordPolicyInfo **_i)
279 {
280         wbcErr wbc_status = WBC_ERR_SUCCESS;
281         struct wbcUserPasswordPolicyInfo *i;
282
283         i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory(
284                 1, sizeof(struct wbcUserPasswordPolicyInfo), NULL);
285         BAIL_ON_PTR_ERROR(i, wbc_status);
286
287         i->min_passwordage      = resp->data.auth.policy.min_passwordage;
288         i->min_length_password  = resp->data.auth.policy.min_length_password;
289         i->password_history     = resp->data.auth.policy.password_history;
290         i->password_properties  = resp->data.auth.policy.password_properties;
291         i->expire               = resp->data.auth.policy.expire;
292
293         *_i = i;
294         i = NULL;
295
296 done:
297         wbcFreeMemory(i);
298         return wbc_status;
299 }
300
301 static void wbcLogonUserInfoDestructor(void *ptr)
302 {
303         struct wbcLogonUserInfo *i = (struct wbcLogonUserInfo *)ptr;
304         wbcFreeMemory(i->info);
305         wbcFreeMemory(i->blobs);
306 }
307
308 static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
309                                     struct wbcLogonUserInfo **_i)
310 {
311         wbcErr wbc_status = WBC_ERR_SUCCESS;
312         struct wbcLogonUserInfo *i;
313
314         i = (struct wbcLogonUserInfo *)wbcAllocateMemory(
315                 1, sizeof(struct wbcLogonUserInfo),
316                 wbcLogonUserInfoDestructor);
317         BAIL_ON_PTR_ERROR(i, wbc_status);
318
319         wbc_status = wbc_create_auth_info(resp, &i->info);
320         BAIL_ON_WBC_ERROR(wbc_status);
321
322         if (resp->data.auth.krb5ccname[0] != '\0') {
323                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
324                                              &i->blobs,
325                                              "krb5ccname",
326                                              0,
327                                              (uint8_t *)resp->data.auth.krb5ccname,
328                                              strlen(resp->data.auth.krb5ccname)+1);
329                 BAIL_ON_WBC_ERROR(wbc_status);
330         }
331
332         if (resp->data.auth.unix_username[0] != '\0') {
333                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
334                                              &i->blobs,
335                                              "unix_username",
336                                              0,
337                                              (uint8_t *)resp->data.auth.unix_username,
338                                              strlen(resp->data.auth.unix_username)+1);
339                 BAIL_ON_WBC_ERROR(wbc_status);
340         }
341
342         *_i = i;
343         i = NULL;
344 done:
345         wbcFreeMemory(i);
346         return wbc_status;
347 }
348
349
350 /* Authenticate with more detailed information */
351 wbcErr wbcCtxAuthenticateUserEx(struct wbcContext *ctx,
352                                 const struct wbcAuthUserParams *params,
353                                 struct wbcAuthUserInfo **info,
354                                 struct wbcAuthErrorInfo **error)
355 {
356         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
357         int cmd = 0;
358         struct winbindd_request request;
359         struct winbindd_response response;
360
361         ZERO_STRUCT(request);
362         ZERO_STRUCT(response);
363
364         if (error) {
365                 *error = NULL;
366         }
367
368         if (!params) {
369                 wbc_status = WBC_ERR_INVALID_PARAM;
370                 BAIL_ON_WBC_ERROR(wbc_status);
371         }
372
373         if (params->level != WBC_AUTH_USER_LEVEL_PAC && !params->account_name) {
374                 wbc_status = WBC_ERR_INVALID_PARAM;
375                 BAIL_ON_WBC_ERROR(wbc_status);
376         }
377
378         /* Initialize request */
379
380         switch (params->level) {
381         case WBC_AUTH_USER_LEVEL_PLAIN:
382                 cmd = WINBINDD_PAM_AUTH;
383                 request.flags = WBFLAG_PAM_INFO3_TEXT |
384                                 WBFLAG_PAM_USER_SESSION_KEY |
385                                 WBFLAG_PAM_LMKEY;
386
387                 if (!params->password.plaintext) {
388                         wbc_status = WBC_ERR_INVALID_PARAM;
389                         BAIL_ON_WBC_ERROR(wbc_status);
390                 }
391
392                 if (params->domain_name && params->domain_name[0]) {
393                         /* We need to get the winbind separator :-( */
394                         struct winbindd_response sep_response;
395
396                         ZERO_STRUCT(sep_response);
397
398                         wbc_status = wbcRequestResponse(ctx, WINBINDD_INFO,
399                                                         NULL, &sep_response);
400                         BAIL_ON_WBC_ERROR(wbc_status);
401
402                         snprintf(request.data.auth.user,
403                                  sizeof(request.data.auth.user)-1,
404                                  "%s%c%s",
405                                  params->domain_name,
406                                  sep_response.data.info.winbind_separator,
407                                  params->account_name);
408                 } else {
409                         strncpy(request.data.auth.user,
410                                 params->account_name,
411                                 sizeof(request.data.auth.user)-1);
412                 }
413
414                 strncpy(request.data.auth.pass,
415                         params->password.plaintext,
416                         sizeof(request.data.auth.pass)-1);
417                 break;
418
419         case WBC_AUTH_USER_LEVEL_HASH:
420                 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
421                 BAIL_ON_WBC_ERROR(wbc_status);
422                 break;
423
424         case WBC_AUTH_USER_LEVEL_RESPONSE:
425                 cmd = WINBINDD_PAM_AUTH_CRAP;
426                 request.flags = WBFLAG_PAM_INFO3_TEXT |
427                                 WBFLAG_PAM_USER_SESSION_KEY |
428                                 WBFLAG_PAM_LMKEY;
429
430                 if (params->password.response.lm_length &&
431                     !params->password.response.lm_data) {
432                         wbc_status = WBC_ERR_INVALID_PARAM;
433                         BAIL_ON_WBC_ERROR(wbc_status);
434                 }
435                 if (params->password.response.lm_length == 0 &&
436                     params->password.response.lm_data) {
437                         wbc_status = WBC_ERR_INVALID_PARAM;
438                         BAIL_ON_WBC_ERROR(wbc_status);
439                 }
440
441                 if (params->password.response.nt_length &&
442                     !params->password.response.nt_data) {
443                         wbc_status = WBC_ERR_INVALID_PARAM;
444                         BAIL_ON_WBC_ERROR(wbc_status);
445                 }
446                 if (params->password.response.nt_length == 0&&
447                     params->password.response.nt_data) {
448                         wbc_status = WBC_ERR_INVALID_PARAM;
449                         BAIL_ON_WBC_ERROR(wbc_status);
450                 }
451
452                 strncpy(request.data.auth_crap.user,
453                         params->account_name,
454                         sizeof(request.data.auth_crap.user)-1);
455                 if (params->domain_name) {
456                         strncpy(request.data.auth_crap.domain,
457                                 params->domain_name,
458                                 sizeof(request.data.auth_crap.domain)-1);
459                 }
460                 if (params->workstation_name) {
461                         strncpy(request.data.auth_crap.workstation,
462                                 params->workstation_name,
463                                 sizeof(request.data.auth_crap.workstation)-1);
464                 }
465
466                 request.data.auth_crap.logon_parameters =
467                                 params->parameter_control;
468
469                 memcpy(request.data.auth_crap.chal,
470                        params->password.response.challenge,
471                        sizeof(request.data.auth_crap.chal));
472
473                 request.data.auth_crap.lm_resp_len =
474                                 MIN(params->password.response.lm_length,
475                                     sizeof(request.data.auth_crap.lm_resp));
476                 if (params->password.response.lm_data) {
477                         memcpy(request.data.auth_crap.lm_resp,
478                                params->password.response.lm_data,
479                                request.data.auth_crap.lm_resp_len);
480                 }
481                 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
482                 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
483                         request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
484                         request.extra_len = params->password.response.nt_length;
485                         request.extra_data.data = (char *)malloc(
486                                 request.extra_len);
487                         if (request.extra_data.data == NULL) {
488                                 wbc_status = WBC_ERR_NO_MEMORY;
489                                 BAIL_ON_WBC_ERROR(wbc_status);
490                         }
491                         memcpy(request.extra_data.data,
492                                params->password.response.nt_data,
493                                request.data.auth_crap.nt_resp_len);
494                 } else if (params->password.response.nt_data) {
495                         memcpy(request.data.auth_crap.nt_resp,
496                                params->password.response.nt_data,
497                                request.data.auth_crap.nt_resp_len);
498                 }
499                 break;
500
501         case WBC_AUTH_USER_LEVEL_PAC:
502                 cmd = WINBINDD_PAM_AUTH_CRAP;
503                 request.flags = WBFLAG_PAM_AUTH_PAC | WBFLAG_PAM_INFO3_TEXT;
504                 request.extra_data.data = malloc(params->password.pac.length);
505                 if (request.extra_data.data == NULL) {
506                         wbc_status = WBC_ERR_NO_MEMORY;
507                         BAIL_ON_WBC_ERROR(wbc_status);
508                 }
509                 memcpy(request.extra_data.data, params->password.pac.data,
510                        params->password.pac.length);
511                 request.extra_len = params->password.pac.length;
512                 break;
513
514         default:
515                 break;
516         }
517
518         if (cmd == 0) {
519                 wbc_status = WBC_ERR_INVALID_PARAM;
520                 BAIL_ON_WBC_ERROR(wbc_status);
521         }
522
523         if (params->flags) {
524                 request.flags |= params->flags;
525         }
526
527         if (cmd == WINBINDD_PAM_AUTH_CRAP) {
528                 wbc_status = wbcRequestResponsePriv(ctx, cmd,
529                                                     &request, &response);
530         } else {
531                 wbc_status = wbcRequestResponse(ctx, cmd,
532                                                 &request, &response);
533         }
534         if (response.data.auth.nt_status != 0) {
535                 if (error) {
536                         wbc_status = wbc_create_error_info(&response,
537                                                            error);
538                         BAIL_ON_WBC_ERROR(wbc_status);
539                 }
540
541                 wbc_status = WBC_ERR_AUTH_ERROR;
542                 BAIL_ON_WBC_ERROR(wbc_status);
543         }
544         BAIL_ON_WBC_ERROR(wbc_status);
545
546         if (info) {
547                 wbc_status = wbc_create_auth_info(&response, info);
548                 BAIL_ON_WBC_ERROR(wbc_status);
549         }
550
551 done:
552         winbindd_free_response(&response);
553
554         free(request.extra_data.data);
555
556         return wbc_status;
557 }
558
559 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
560                              struct wbcAuthUserInfo **info,
561                              struct wbcAuthErrorInfo **error)
562 {
563         return wbcCtxAuthenticateUserEx(NULL, params, info, error);
564 }
565
566 /* Trigger a verification of the trust credentials of a specific domain */
567 wbcErr wbcCtxCheckTrustCredentials(struct wbcContext *ctx, const char *domain,
568                                    struct wbcAuthErrorInfo **error)
569 {
570         struct winbindd_request request;
571         struct winbindd_response response;
572         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
573
574         ZERO_STRUCT(request);
575         ZERO_STRUCT(response);
576
577         if (domain) {
578                 strncpy(request.domain_name, domain,
579                         sizeof(request.domain_name)-1);
580         }
581
582         /* Send request */
583
584         wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHECK_MACHACC,
585                                             &request, &response);
586         if (response.data.auth.nt_status != 0) {
587                 if (error) {
588                         wbc_status = wbc_create_error_info(&response,
589                                                            error);
590                         BAIL_ON_WBC_ERROR(wbc_status);
591                 }
592
593                 wbc_status = WBC_ERR_AUTH_ERROR;
594                 BAIL_ON_WBC_ERROR(wbc_status);
595         }
596         BAIL_ON_WBC_ERROR(wbc_status);
597
598  done:
599         return wbc_status;
600 }
601
602 wbcErr wbcCheckTrustCredentials(const char *domain,
603                                 struct wbcAuthErrorInfo **error)
604 {
605         return wbcCtxCheckTrustCredentials(NULL, domain, error);
606 }
607
608 /* Trigger a change of the trust credentials for a specific domain */
609 wbcErr wbcCtxChangeTrustCredentials(struct wbcContext *ctx, const char *domain,
610                                     struct wbcAuthErrorInfo **error)
611 {
612         struct winbindd_request request;
613         struct winbindd_response response;
614         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
615
616         ZERO_STRUCT(request);
617         ZERO_STRUCT(response);
618
619         if (domain) {
620                 strncpy(request.domain_name, domain,
621                         sizeof(request.domain_name)-1);
622         }
623
624         /* Send request */
625
626         wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHANGE_MACHACC,
627                                             &request, &response);
628         if (response.data.auth.nt_status != 0) {
629                 if (error) {
630                         wbc_status = wbc_create_error_info(&response,
631                                                            error);
632                         BAIL_ON_WBC_ERROR(wbc_status);
633                 }
634
635                 wbc_status = WBC_ERR_AUTH_ERROR;
636                 BAIL_ON_WBC_ERROR(wbc_status);
637         }
638         BAIL_ON_WBC_ERROR(wbc_status);
639
640  done:
641         return wbc_status;
642 }
643
644 wbcErr wbcChangeTrustCredentials(const char *domain,
645                                  struct wbcAuthErrorInfo **error)
646 {
647         return wbcCtxChangeTrustCredentials(NULL, domain, error);
648 }
649
650 /*
651  * Trigger a no-op NETLOGON call. Lightweight version of
652  * wbcCheckTrustCredentials
653  */
654 wbcErr wbcCtxPingDc(struct wbcContext *ctx, const char *domain,
655                     struct wbcAuthErrorInfo **error)
656 {
657         return wbcCtxPingDc2(ctx, domain, error, NULL);
658 }
659
660 wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
661 {
662         return wbcPingDc2(domain, error, NULL);
663 }
664
665 /*
666  * Trigger a no-op NETLOGON call. Lightweight version of
667  * wbcCheckTrustCredentials, optionally return attempted DC
668  */
669 wbcErr wbcCtxPingDc2(struct wbcContext *ctx, const char *domain,
670                      struct wbcAuthErrorInfo **error, char **dcname)
671 {
672         struct winbindd_request request;
673         struct winbindd_response response;
674         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
675
676         ZERO_STRUCT(request);
677         ZERO_STRUCT(response);
678
679         if (domain) {
680                 strncpy(request.domain_name, domain,
681                         sizeof(request.domain_name)-1);
682         }
683
684         /* Send request */
685
686         wbc_status = wbcRequestResponse(ctx, WINBINDD_PING_DC,
687                                         &request,
688                                         &response);
689
690         if (dcname && response.extra_data.data) {
691                 size_t len;
692
693                 len = response.length - sizeof(struct winbindd_response);
694                 *dcname = wbcAllocateMemory(1, len, NULL);
695                 BAIL_ON_PTR_ERROR(*dcname, wbc_status);
696
697                 strlcpy(*dcname, response.extra_data.data, len);
698         }
699
700         if (response.data.auth.nt_status != 0) {
701                 if (error) {
702                         wbc_status = wbc_create_error_info(&response,
703                                                            error);
704                         BAIL_ON_WBC_ERROR(wbc_status);
705                 }
706
707                 wbc_status = WBC_ERR_AUTH_ERROR;
708                 BAIL_ON_WBC_ERROR(wbc_status);
709         }
710         BAIL_ON_WBC_ERROR(wbc_status);
711
712  done:
713         return wbc_status;
714 }
715
716 wbcErr wbcPingDc2(const char *domain, struct wbcAuthErrorInfo **error,
717                   char **dcname)
718 {
719         return wbcCtxPingDc2(NULL, domain, error, dcname);
720 }
721
722 /* Trigger an extended logoff notification to Winbind for a specific user */
723 wbcErr wbcCtxLogoffUserEx(struct wbcContext *ctx,
724                           const struct wbcLogoffUserParams *params,
725                           struct wbcAuthErrorInfo **error)
726 {
727         struct winbindd_request request;
728         struct winbindd_response response;
729         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
730         int i;
731
732         /* validate input */
733
734         if (!params || !params->username) {
735                 wbc_status = WBC_ERR_INVALID_PARAM;
736                 BAIL_ON_WBC_ERROR(wbc_status);
737         }
738
739         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
740                 wbc_status = WBC_ERR_INVALID_PARAM;
741                 BAIL_ON_WBC_ERROR(wbc_status);
742         }
743         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
744                 wbc_status = WBC_ERR_INVALID_PARAM;
745                 BAIL_ON_WBC_ERROR(wbc_status);
746         }
747
748         ZERO_STRUCT(request);
749         ZERO_STRUCT(response);
750
751         strncpy(request.data.logoff.user, params->username,
752                 sizeof(request.data.logoff.user)-1);
753
754         for (i=0; i<params->num_blobs; i++) {
755
756                 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
757                         if (params->blobs[i].blob.data) {
758                                 strncpy(request.data.logoff.krb5ccname,
759                                         (const char *)params->blobs[i].blob.data,
760                                         sizeof(request.data.logoff.krb5ccname) - 1);
761                         }
762                         continue;
763                 }
764
765                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
766                         if (params->blobs[i].blob.data) {
767                                 memcpy(&request.data.logoff.uid,
768                                         params->blobs[i].blob.data,
769                                         MIN(params->blobs[i].blob.length,
770                                             sizeof(request.data.logoff.uid)));
771                         }
772                         continue;
773                 }
774
775                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
776                         if (params->blobs[i].blob.data) {
777                                 memcpy(&request.flags,
778                                         params->blobs[i].blob.data,
779                                         MIN(params->blobs[i].blob.length,
780                                             sizeof(request.flags)));
781                         }
782                         continue;
783                 }
784         }
785
786         /* Send request */
787
788         wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
789                                         &request,
790                                         &response);
791
792         /* Take the response above and return it to the caller */
793         if (response.data.auth.nt_status != 0) {
794                 if (error) {
795                         wbc_status = wbc_create_error_info(&response,
796                                                            error);
797                         BAIL_ON_WBC_ERROR(wbc_status);
798                 }
799
800                 wbc_status = WBC_ERR_AUTH_ERROR;
801                 BAIL_ON_WBC_ERROR(wbc_status);
802         }
803         BAIL_ON_WBC_ERROR(wbc_status);
804
805  done:
806         return wbc_status;
807 }
808
809 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
810                        struct wbcAuthErrorInfo **error)
811 {
812         return wbcCtxLogoffUserEx(NULL, params, error);
813 }
814
815 /* Trigger a logoff notification to Winbind for a specific user */
816 wbcErr wbcCtxLogoffUser(struct wbcContext *ctx,
817                         const char *username, uid_t uid,
818                         const char *ccfilename)
819 {
820         struct winbindd_request request;
821         struct winbindd_response response;
822         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
823
824         /* validate input */
825
826         if (!username) {
827                 wbc_status = WBC_ERR_INVALID_PARAM;
828                 BAIL_ON_WBC_ERROR(wbc_status);
829         }
830
831         ZERO_STRUCT(request);
832         ZERO_STRUCT(response);
833
834         strncpy(request.data.logoff.user, username,
835                 sizeof(request.data.logoff.user)-1);
836         request.data.logoff.uid = uid;
837
838         if (ccfilename) {
839                 strncpy(request.data.logoff.krb5ccname, ccfilename,
840                         sizeof(request.data.logoff.krb5ccname)-1);
841         }
842
843         /* Send request */
844
845         wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
846                                         &request,
847                                         &response);
848
849         /* Take the response above and return it to the caller */
850
851  done:
852         return wbc_status;
853 }
854
855 wbcErr wbcLogoffUser(const char *username,
856                      uid_t uid,
857                      const char *ccfilename)
858 {
859         return wbcCtxLogoffUser(NULL, username, uid, ccfilename);
860 }
861
862 /* Change a password for a user with more detailed information upon failure */
863 wbcErr wbcCtxChangeUserPasswordEx(struct wbcContext *ctx,
864                         const struct wbcChangePasswordParams *params,
865                         struct wbcAuthErrorInfo **error,
866                         enum wbcPasswordChangeRejectReason *reject_reason,
867                         struct wbcUserPasswordPolicyInfo **policy)
868 {
869         struct winbindd_request request;
870         struct winbindd_response response;
871         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
872         int cmd = 0;
873
874         /* validate input */
875
876         if (!params->account_name) {
877                 wbc_status = WBC_ERR_INVALID_PARAM;
878                 goto done;
879         }
880
881         if (error) {
882                 *error = NULL;
883         }
884
885         if (policy) {
886                 *policy = NULL;
887         }
888
889         if (reject_reason) {
890                 *reject_reason = -1;
891         }
892
893         ZERO_STRUCT(request);
894         ZERO_STRUCT(response);
895
896         switch (params->level) {
897         case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
898                 cmd = WINBINDD_PAM_CHAUTHTOK;
899
900                 if (!params->account_name) {
901                         wbc_status = WBC_ERR_INVALID_PARAM;
902                         goto done;
903                 }
904
905                 strncpy(request.data.chauthtok.user, params->account_name,
906                         sizeof(request.data.chauthtok.user) - 1);
907
908                 if (params->old_password.plaintext) {
909                         strncpy(request.data.chauthtok.oldpass,
910                                 params->old_password.plaintext,
911                                 sizeof(request.data.chauthtok.oldpass) - 1);
912                 }
913
914                 if (params->new_password.plaintext) {
915                         strncpy(request.data.chauthtok.newpass,
916                                 params->new_password.plaintext,
917                                 sizeof(request.data.chauthtok.newpass) - 1);
918                 }
919                 break;
920
921         case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
922                 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
923
924                 if (!params->account_name || !params->domain_name) {
925                         wbc_status = WBC_ERR_INVALID_PARAM;
926                         goto done;
927                 }
928
929                 if (params->old_password.response.old_lm_hash_enc_length &&
930                     !params->old_password.response.old_lm_hash_enc_data) {
931                         wbc_status = WBC_ERR_INVALID_PARAM;
932                         goto done;
933                 }
934
935                 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
936                     params->old_password.response.old_lm_hash_enc_data) {
937                         wbc_status = WBC_ERR_INVALID_PARAM;
938                         goto done;
939                 }
940
941                 if (params->old_password.response.old_nt_hash_enc_length &&
942                     !params->old_password.response.old_nt_hash_enc_data) {
943                         wbc_status = WBC_ERR_INVALID_PARAM;
944                         goto done;
945                 }
946
947                 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
948                     params->old_password.response.old_nt_hash_enc_data) {
949                         wbc_status = WBC_ERR_INVALID_PARAM;
950                         goto done;
951                 }
952
953                 if (params->new_password.response.lm_length &&
954                     !params->new_password.response.lm_data) {
955                         wbc_status = WBC_ERR_INVALID_PARAM;
956                         goto done;
957                 }
958
959                 if (params->new_password.response.lm_length == 0 &&
960                     params->new_password.response.lm_data) {
961                         wbc_status = WBC_ERR_INVALID_PARAM;
962                         goto done;
963                 }
964
965                 if (params->new_password.response.nt_length &&
966                     !params->new_password.response.nt_data) {
967                         wbc_status = WBC_ERR_INVALID_PARAM;
968                         goto done;
969                 }
970
971                 if (params->new_password.response.nt_length == 0 &&
972                     params->new_password.response.nt_data) {
973                         wbc_status = WBC_ERR_INVALID_PARAM;
974                         goto done;
975                 }
976
977                 strncpy(request.data.chng_pswd_auth_crap.user,
978                         params->account_name,
979                         sizeof(request.data.chng_pswd_auth_crap.user) - 1);
980
981                 strncpy(request.data.chng_pswd_auth_crap.domain,
982                         params->domain_name,
983                         sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
984
985                 if (params->new_password.response.nt_data) {
986                         request.data.chng_pswd_auth_crap.new_nt_pswd_len =
987                                 params->new_password.response.nt_length;
988                         memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
989                                params->new_password.response.nt_data,
990                                request.data.chng_pswd_auth_crap.new_nt_pswd_len);
991                 }
992
993                 if (params->new_password.response.lm_data) {
994                         request.data.chng_pswd_auth_crap.new_lm_pswd_len =
995                                 params->new_password.response.lm_length;
996                         memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
997                                params->new_password.response.lm_data,
998                                request.data.chng_pswd_auth_crap.new_lm_pswd_len);
999                 }
1000
1001                 if (params->old_password.response.old_nt_hash_enc_data) {
1002                         request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
1003                                 params->old_password.response.old_nt_hash_enc_length;
1004                         memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
1005                                params->old_password.response.old_nt_hash_enc_data,
1006                                request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
1007                 }
1008
1009                 if (params->old_password.response.old_lm_hash_enc_data) {
1010                         request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
1011                                 params->old_password.response.old_lm_hash_enc_length;
1012                         memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
1013                                params->old_password.response.old_lm_hash_enc_data,
1014                                request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
1015                 }
1016
1017                 break;
1018         default:
1019                 wbc_status = WBC_ERR_INVALID_PARAM;
1020                 goto done;
1021                 break;
1022         }
1023
1024         /* Send request */
1025
1026         wbc_status = wbcRequestResponse(ctx, cmd,
1027                                         &request,
1028                                         &response);
1029         if (WBC_ERROR_IS_OK(wbc_status)) {
1030                 goto done;
1031         }
1032
1033         /* Take the response above and return it to the caller */
1034
1035         if (response.data.auth.nt_status != 0) {
1036                 if (error) {
1037                         wbc_status = wbc_create_error_info(&response,
1038                                                            error);
1039                         BAIL_ON_WBC_ERROR(wbc_status);
1040                 }
1041
1042         }
1043
1044         if (policy) {
1045                 wbc_status = wbc_create_password_policy_info(&response,
1046                                                              policy);
1047                 BAIL_ON_WBC_ERROR(wbc_status);
1048         }
1049
1050         if (reject_reason) {
1051                 *reject_reason = response.data.auth.reject_reason;
1052         }
1053
1054         wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
1055         BAIL_ON_WBC_ERROR(wbc_status);
1056
1057  done:
1058         return wbc_status;
1059 }
1060
1061 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
1062                               struct wbcAuthErrorInfo **error,
1063                               enum wbcPasswordChangeRejectReason *reject_reason,
1064                               struct wbcUserPasswordPolicyInfo **policy)
1065 {
1066         return wbcCtxChangeUserPasswordEx(NULL, params, error,
1067                                           reject_reason, policy);
1068 }
1069
1070 /* Change a password for a user */
1071 wbcErr wbcCtxChangeUserPassword(struct wbcContext *ctx,
1072                                 const char *username,
1073                                 const char *old_password,
1074                                 const char *new_password)
1075 {
1076         wbcErr wbc_status = WBC_ERR_SUCCESS;
1077         struct wbcChangePasswordParams params;
1078
1079         ZERO_STRUCT(params);
1080
1081         params.account_name             = username;
1082         params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
1083         params.old_password.plaintext   = old_password;
1084         params.new_password.plaintext   = new_password;
1085
1086         wbc_status = wbcCtxChangeUserPasswordEx(ctx, &params,
1087                                                 NULL,
1088                                                 NULL,
1089                                                 NULL);
1090         BAIL_ON_WBC_ERROR(wbc_status);
1091
1092 done:
1093         return wbc_status;
1094 }
1095
1096 wbcErr wbcChangeUserPassword(const char *username,
1097                              const char *old_password,
1098                              const char *new_password)
1099 {
1100         return wbcCtxChangeUserPassword(NULL, username,
1101                                         old_password, new_password);
1102 }
1103
1104 /* Logon a User */
1105 wbcErr wbcCtxLogonUser(struct wbcContext *ctx,
1106                        const struct wbcLogonUserParams *params,
1107                        struct wbcLogonUserInfo **info,
1108                        struct wbcAuthErrorInfo **error,
1109                        struct wbcUserPasswordPolicyInfo **policy)
1110 {
1111         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1112         struct winbindd_request request;
1113         struct winbindd_response response;
1114         uint32_t i;
1115
1116         ZERO_STRUCT(request);
1117         ZERO_STRUCT(response);
1118
1119         if (info) {
1120                 *info = NULL;
1121         }
1122         if (error) {
1123                 *error = NULL;
1124         }
1125         if (policy) {
1126                 *policy = NULL;
1127         }
1128
1129         if (!params) {
1130                 wbc_status = WBC_ERR_INVALID_PARAM;
1131                 BAIL_ON_WBC_ERROR(wbc_status);
1132         }
1133
1134         if (!params->username) {
1135                 wbc_status = WBC_ERR_INVALID_PARAM;
1136                 BAIL_ON_WBC_ERROR(wbc_status);
1137         }
1138
1139         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1140                 wbc_status = WBC_ERR_INVALID_PARAM;
1141                 BAIL_ON_WBC_ERROR(wbc_status);
1142         }
1143         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1144                 wbc_status = WBC_ERR_INVALID_PARAM;
1145                 BAIL_ON_WBC_ERROR(wbc_status);
1146         }
1147
1148         /* Initialize request */
1149
1150         request.flags = WBFLAG_PAM_INFO3_TEXT |
1151                         WBFLAG_PAM_USER_SESSION_KEY |
1152                         WBFLAG_PAM_LMKEY;
1153
1154         if (!params->password) {
1155                 wbc_status = WBC_ERR_INVALID_PARAM;
1156                 BAIL_ON_WBC_ERROR(wbc_status);
1157         }
1158
1159         strncpy(request.data.auth.user,
1160                 params->username,
1161                 sizeof(request.data.auth.user)-1);
1162
1163         strncpy(request.data.auth.pass,
1164                 params->password,
1165                 sizeof(request.data.auth.pass)-1);
1166
1167         for (i=0; i<params->num_blobs; i++) {
1168
1169                 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1170                         if (params->blobs[i].blob.data) {
1171                                 strncpy(request.data.auth.krb5_cc_type,
1172                                         (const char *)params->blobs[i].blob.data,
1173                                         sizeof(request.data.auth.krb5_cc_type) - 1);
1174                         }
1175                         continue;
1176                 }
1177
1178                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1179                         if (params->blobs[i].blob.data) {
1180                                 memcpy(&request.data.auth.uid,
1181                                         params->blobs[i].blob.data,
1182                                         MIN(sizeof(request.data.auth.uid),
1183                                             params->blobs[i].blob.length));
1184                         }
1185                         continue;
1186                 }
1187
1188                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1189                         if (params->blobs[i].blob.data) {
1190                                 uint32_t flags;
1191                                 memcpy(&flags,
1192                                         params->blobs[i].blob.data,
1193                                         MIN(sizeof(flags),
1194                                             params->blobs[i].blob.length));
1195                                 request.flags |= flags;
1196                         }
1197                         continue;
1198                 }
1199
1200                 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1201                         if (params->blobs[i].blob.data &&
1202                             params->blobs[i].blob.data[0] > 0) {
1203                                 strncpy(request.data.auth.require_membership_of_sid,
1204                                         (const char *)params->blobs[i].blob.data,
1205                                         sizeof(request.data.auth.require_membership_of_sid) - 1);
1206                         }
1207                         continue;
1208                 }
1209         }
1210
1211         wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_AUTH,
1212                                         &request,
1213                                         &response);
1214
1215         if (response.data.auth.nt_status != 0) {
1216                 if (error) {
1217                         wbc_status = wbc_create_error_info(&response,
1218                                                            error);
1219                         BAIL_ON_WBC_ERROR(wbc_status);
1220                 }
1221
1222                 wbc_status = WBC_ERR_AUTH_ERROR;
1223                 BAIL_ON_WBC_ERROR(wbc_status);
1224         }
1225         BAIL_ON_WBC_ERROR(wbc_status);
1226
1227         if (info) {
1228                 wbc_status = wbc_create_logon_info(&response,
1229                                                    info);
1230                 BAIL_ON_WBC_ERROR(wbc_status);
1231         }
1232
1233         if (policy) {
1234                 wbc_status = wbc_create_password_policy_info(&response,
1235                                                              policy);
1236                 BAIL_ON_WBC_ERROR(wbc_status);
1237         }
1238
1239 done:
1240         winbindd_free_response(&response);
1241
1242         return wbc_status;
1243 }
1244
1245 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
1246                     struct wbcLogonUserInfo **info,
1247                     struct wbcAuthErrorInfo **error,
1248                     struct wbcUserPasswordPolicyInfo **policy)
1249 {
1250         return wbcCtxLogonUser(NULL, params, info, error, policy);
1251 }
1252
1253 static void wbcCredentialCacheInfoDestructor(void *ptr)
1254 {
1255         struct wbcCredentialCacheInfo *i =
1256                 (struct wbcCredentialCacheInfo *)ptr;
1257         wbcFreeMemory(i->blobs);
1258 }
1259
1260 /* Authenticate a user with cached credentials */
1261 wbcErr wbcCtxCredentialCache(struct wbcContext *ctx,
1262                              struct wbcCredentialCacheParams *params,
1263                              struct wbcCredentialCacheInfo **info,
1264                              struct wbcAuthErrorInfo **error)
1265 {
1266         wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1267         struct wbcCredentialCacheInfo *result = NULL;
1268         struct winbindd_request request;
1269         struct winbindd_response response;
1270         struct wbcNamedBlob *initial_blob = NULL;
1271         struct wbcNamedBlob *challenge_blob = NULL;
1272         int i;
1273
1274         ZERO_STRUCT(request);
1275         ZERO_STRUCT(response);
1276
1277         *info = NULL;
1278
1279         if (error != NULL) {
1280                 *error = NULL;
1281         }
1282         if ((params == NULL)
1283             || (params->account_name == NULL)
1284             || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1285                 status = WBC_ERR_INVALID_PARAM;
1286                 goto fail;
1287         }
1288
1289         for (i=0; i<params->num_blobs; i++) {
1290                 /*
1291                  * Older callers may used to provide the NEGOTIATE request
1292                  * as "initial_blob", but it was completely ignored by winbindd.
1293                  *
1294                  * So we keep ignoring it.
1295                  *
1296                  * A new callers that is capable to support "new_spnego",
1297                  * will provide the NEGOTIATE request as "negotiate_blob"
1298                  * instead.
1299                  */
1300                 if (strcasecmp(params->blobs[i].name, "negotiate_blob") == 0) {
1301                         if (initial_blob != NULL) {
1302                                 status = WBC_ERR_INVALID_PARAM;
1303                                 goto fail;
1304                         }
1305                         initial_blob = &params->blobs[i];
1306                         continue;
1307                 }
1308                 if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1309                         if (challenge_blob != NULL) {
1310                                 status = WBC_ERR_INVALID_PARAM;
1311                                 goto fail;
1312                         }
1313                         challenge_blob = &params->blobs[i];
1314                         continue;
1315                 }
1316         }
1317
1318         if (params->domain_name != NULL) {
1319                 status = wbcRequestResponse(ctx, WINBINDD_INFO,
1320                                             NULL, &response);
1321                 if (!WBC_ERROR_IS_OK(status)) {
1322                         goto fail;
1323                 }
1324                 snprintf(request.data.ccache_ntlm_auth.user,
1325                          sizeof(request.data.ccache_ntlm_auth.user)-1,
1326                          "%s%c%s", params->domain_name,
1327                          response.data.info.winbind_separator,
1328                          params->account_name);
1329         } else {
1330                 strncpy(request.data.ccache_ntlm_auth.user,
1331                         params->account_name,
1332                         sizeof(request.data.ccache_ntlm_auth.user)-1);
1333         }
1334         request.data.ccache_ntlm_auth.uid = getuid();
1335
1336         request.data.ccache_ntlm_auth.initial_blob_len = 0;
1337         request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1338         request.extra_len = 0;
1339
1340         if (initial_blob != NULL) {
1341                 request.data.ccache_ntlm_auth.initial_blob_len =
1342                         initial_blob->blob.length;
1343                 request.extra_len += initial_blob->blob.length;
1344         }
1345         if (challenge_blob != NULL) {
1346                 request.data.ccache_ntlm_auth.challenge_blob_len =
1347                         challenge_blob->blob.length;
1348                 request.extra_len += challenge_blob->blob.length;
1349         }
1350
1351         if (request.extra_len != 0) {
1352                 request.extra_data.data = (char *)malloc(request.extra_len);
1353                 if (request.extra_data.data == NULL) {
1354                         status = WBC_ERR_NO_MEMORY;
1355                         goto fail;
1356                 }
1357         }
1358         if (initial_blob != NULL) {
1359                 memcpy(request.extra_data.data,
1360                        initial_blob->blob.data, initial_blob->blob.length);
1361         }
1362         if (challenge_blob != NULL) {
1363                 memcpy(request.extra_data.data
1364                        + request.data.ccache_ntlm_auth.initial_blob_len,
1365                        challenge_blob->blob.data,
1366                        challenge_blob->blob.length);
1367         }
1368
1369         status = wbcRequestResponse(ctx, WINBINDD_CCACHE_NTLMAUTH,
1370                                     &request, &response);
1371         if (!WBC_ERROR_IS_OK(status)) {
1372                 goto fail;
1373         }
1374
1375         result = (struct wbcCredentialCacheInfo *)wbcAllocateMemory(
1376                 1, sizeof(struct wbcCredentialCacheInfo),
1377                 wbcCredentialCacheInfoDestructor);
1378         if (result == NULL) {
1379                 status = WBC_ERR_NO_MEMORY;
1380                 goto fail;
1381         }
1382         result->num_blobs = 0;
1383         result->blobs = NULL;
1384         status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1385                                  "auth_blob", 0,
1386                                  (uint8_t *)response.extra_data.data,
1387                                  response.data.ccache_ntlm_auth.auth_blob_len);
1388         if (!WBC_ERROR_IS_OK(status)) {
1389                 goto fail;
1390         }
1391         status = wbcAddNamedBlob(
1392                 &result->num_blobs, &result->blobs, "session_key", 0,
1393                 response.data.ccache_ntlm_auth.session_key,
1394                 sizeof(response.data.ccache_ntlm_auth.session_key));
1395         if (!WBC_ERROR_IS_OK(status)) {
1396                 goto fail;
1397         }
1398         if (response.data.ccache_ntlm_auth.new_spnego) {
1399                 status = wbcAddNamedBlob(
1400                         &result->num_blobs, &result->blobs, "new_spnego", 0,
1401                         &response.data.ccache_ntlm_auth.new_spnego,
1402                         sizeof(response.data.ccache_ntlm_auth.new_spnego));
1403                 if (!WBC_ERROR_IS_OK(status)) {
1404                         goto fail;
1405                 }
1406         }
1407
1408         *info = result;
1409         result = NULL;
1410         status = WBC_ERR_SUCCESS;
1411 fail:
1412         free(request.extra_data.data);
1413         winbindd_free_response(&response);
1414         wbcFreeMemory(result);
1415         return status;
1416 }
1417
1418 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1419                           struct wbcCredentialCacheInfo **info,
1420                           struct wbcAuthErrorInfo **error)
1421 {
1422         return wbcCtxCredentialCache(NULL, params, info, error);
1423 }
1424
1425 /* Authenticate a user with cached credentials */
1426 wbcErr wbcCtxCredentialSave(struct wbcContext *ctx,
1427                             const char *user, const char *password)
1428 {
1429         struct winbindd_request request;
1430         struct winbindd_response response;
1431
1432         ZERO_STRUCT(request);
1433         ZERO_STRUCT(response);
1434
1435         strncpy(request.data.ccache_save.user, user,
1436                 sizeof(request.data.ccache_save.user)-1);
1437         strncpy(request.data.ccache_save.pass, password,
1438                 sizeof(request.data.ccache_save.pass)-1);
1439         request.data.ccache_save.uid = getuid();
1440
1441         return wbcRequestResponse(ctx, WINBINDD_CCACHE_SAVE, &request, &response);
1442 }
1443
1444 wbcErr wbcCredentialSave(const char *user, const char *password)
1445 {
1446         return wbcCtxCredentialSave(NULL, user, password);
1447 }