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