Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[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
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 3 of the License, or (at your option) any later version.
13
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Lesser General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* Required Headers */
24
25 #include "replace.h"
26 #include "libwbclient.h"
27
28 /* Authenticate a username/password pair */
29 wbcErr wbcAuthenticateUser(const char *username,
30                            const char *password)
31 {
32         wbcErr wbc_status = WBC_ERR_SUCCESS;
33         struct wbcAuthUserParams params;
34
35         ZERO_STRUCT(params);
36
37         params.account_name             = username;
38         params.level                    = WBC_AUTH_USER_LEVEL_PLAIN;
39         params.password.plaintext       = password;
40
41         wbc_status = wbcAuthenticateUserEx(&params, NULL, NULL);
42         BAIL_ON_WBC_ERROR(wbc_status);
43
44 done:
45         return wbc_status;
46 }
47
48 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
49                                    const struct winbindd_response *resp,
50                                    struct wbcAuthUserInfo **_i)
51 {
52         wbcErr wbc_status = WBC_ERR_SUCCESS;
53         struct wbcAuthUserInfo *i;
54         struct wbcDomainSid domain_sid;
55         char *p;
56         uint32_t sn = 0;
57         uint32_t j;
58
59         i = talloc(mem_ctx, struct wbcAuthUserInfo);
60         BAIL_ON_PTR_ERROR(i, wbc_status);
61
62         i->user_flags   = resp->data.auth.info3.user_flgs;
63
64         i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
65         BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
66         i->user_principal= NULL;
67         i->full_name    = talloc_strdup(i, resp->data.auth.info3.full_name);
68         BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
69         i->domain_name  = talloc_strdup(i, resp->data.auth.info3.logon_dom);
70         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
71         i->dns_domain_name= NULL;
72
73         i->acct_flags   = resp->data.auth.info3.acct_flags;
74         memcpy(i->user_session_key,
75                resp->data.auth.user_session_key,
76                sizeof(i->user_session_key));
77         memcpy(i->lm_session_key,
78                resp->data.auth.first_8_lm_hash,
79                sizeof(i->lm_session_key));
80
81         i->logon_count          = resp->data.auth.info3.logon_count;
82         i->bad_password_count   = resp->data.auth.info3.bad_pw_count;
83
84         i->logon_time           = resp->data.auth.info3.logon_time;
85         i->logoff_time          = resp->data.auth.info3.logoff_time;
86         i->kickoff_time         = resp->data.auth.info3.kickoff_time;
87         i->pass_last_set_time   = resp->data.auth.info3.pass_last_set_time;
88         i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
89         i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
90
91         i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
92         BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
93         i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
94         BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
95         i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
96         BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
97         i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
98         BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
99         i->home_drive   = talloc_strdup(i, resp->data.auth.info3.dir_drive);
100         BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
101
102         i->num_sids     = 2;
103         i->num_sids     += resp->data.auth.info3.num_groups;
104         i->num_sids     += resp->data.auth.info3.num_other_sids;
105
106         i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
107         BAIL_ON_PTR_ERROR(i->sids, wbc_status);
108
109         wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
110                                     &domain_sid);
111         BAIL_ON_WBC_ERROR(wbc_status);
112
113 #define _SID_COMPOSE(s, d, r, a) { \
114         (s).sid = d; \
115         if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \
116                 (s).sid.sub_auths[(s).sid.num_auths++] = r; \
117         } else { \
118                 wbc_status = WBC_ERR_INVALID_SID; \
119                 BAIL_ON_WBC_ERROR(wbc_status); \
120         } \
121         (s).attributes = a; \
122 } while (0)
123
124         sn = 0;
125         _SID_COMPOSE(i->sids[sn], domain_sid,
126                      resp->data.auth.info3.user_rid,
127                      0);
128         sn++;
129         _SID_COMPOSE(i->sids[sn], domain_sid,
130                      resp->data.auth.info3.group_rid,
131                      0);
132         sn++;
133
134         p = (char *)resp->extra_data.data;
135         if (!p) {
136                 wbc_status = WBC_ERR_INVALID_RESPONSE;
137                 BAIL_ON_WBC_ERROR(wbc_status);
138         }
139
140         for (j=0; j < resp->data.auth.info3.num_groups; j++) {
141                 uint32_t rid;
142                 uint32_t attrs;
143                 int ret;
144                 char *s = p;
145                 char *e = strchr(p, '\n');
146                 if (!e) {
147                         wbc_status = WBC_ERR_INVALID_RESPONSE;
148                         BAIL_ON_WBC_ERROR(wbc_status);
149                 }
150                 e[0] = '\0';
151                 p = &e[1];
152
153                 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
154                 if (ret != 2) {
155                         wbc_status = WBC_ERR_INVALID_RESPONSE;
156                         BAIL_ON_WBC_ERROR(wbc_status);
157                 }
158
159                 _SID_COMPOSE(i->sids[sn], domain_sid,
160                              rid, attrs);
161                 sn++;
162         }
163
164         for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
165                 uint32_t attrs;
166                 int ret;
167                 char *s = p;
168                 char *a;
169                 char *e = strchr(p, '\n');
170                 if (!e) {
171                         wbc_status = WBC_ERR_INVALID_RESPONSE;
172                         BAIL_ON_WBC_ERROR(wbc_status);
173                 }
174                 e[0] = '\0';
175                 p = &e[1];
176
177                 e = strchr(s, ':');
178                 if (!e) {
179                         wbc_status = WBC_ERR_INVALID_RESPONSE;
180                         BAIL_ON_WBC_ERROR(wbc_status);
181                 }
182                 e[0] = '\0';
183                 a = &e[1];
184
185                 ret = sscanf(a, "0x%08X",
186                              &attrs);
187                 if (ret != 1) {
188                         wbc_status = WBC_ERR_INVALID_RESPONSE;
189                         BAIL_ON_WBC_ERROR(wbc_status);
190                 }
191
192                 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
193                 BAIL_ON_WBC_ERROR(wbc_status);
194
195                 i->sids[sn].attributes = attrs;
196                 sn++;
197         }
198
199         i->num_sids = sn;
200
201         *_i = i;
202         i = NULL;
203 done:
204         talloc_free(i);
205         return wbc_status;
206 }
207
208 static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
209                                   const struct winbindd_response *resp,
210                                   struct wbcAuthErrorInfo **_e)
211 {
212         wbcErr wbc_status = WBC_ERR_SUCCESS;
213         struct wbcAuthErrorInfo *e;
214
215         e = talloc(mem_ctx, struct wbcAuthErrorInfo);
216         BAIL_ON_PTR_ERROR(e, wbc_status);
217
218         e->nt_status = resp->data.auth.nt_status;
219         e->pam_error = resp->data.auth.pam_error;
220         e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
221         BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
222
223         e->display_string = talloc_strdup(e, resp->data.auth.error_string);
224         BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
225
226         *_e = e;
227         e = NULL;
228
229 done:
230         talloc_free(e);
231         return wbc_status;
232 }
233
234 static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx,
235                                               const struct winbindd_response *resp,
236                                               struct wbcUserPasswordPolicyInfo **_i)
237 {
238         wbcErr wbc_status = WBC_ERR_SUCCESS;
239         struct wbcUserPasswordPolicyInfo *i;
240
241         i = talloc(mem_ctx, struct wbcUserPasswordPolicyInfo);
242         BAIL_ON_PTR_ERROR(i, wbc_status);
243
244         i->min_passwordage      = resp->data.auth.policy.min_passwordage;
245         i->min_length_password  = resp->data.auth.policy.min_length_password;
246         i->password_history     = resp->data.auth.policy.password_history;
247         i->password_properties  = resp->data.auth.policy.password_properties;
248         i->expire               = resp->data.auth.policy.expire;
249
250         *_i = i;
251         i = NULL;
252
253 done:
254         talloc_free(i);
255         return wbc_status;
256 }
257
258 static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx,
259                                     struct winbindd_response *resp,
260                                     struct wbcLogonUserInfo **_i)
261 {
262         wbcErr wbc_status = WBC_ERR_SUCCESS;
263         struct wbcLogonUserInfo *i;
264
265         i = talloc_zero(mem_ctx, struct wbcLogonUserInfo);
266         BAIL_ON_PTR_ERROR(i, wbc_status);
267
268         wbc_status = wbc_create_auth_info(i, resp, &i->info);
269         BAIL_ON_WBC_ERROR(wbc_status);
270
271         if (resp->data.auth.krb5ccname &&
272             strlen(resp->data.auth.krb5ccname)) {
273                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
274                                              &i->blobs,
275                                              "krb5ccname",
276                                              0,
277                                              (uint8_t *)resp->data.auth.krb5ccname,
278                                              strlen(resp->data.auth.krb5ccname)+1);
279                 BAIL_ON_WBC_ERROR(wbc_status);
280         }
281
282         if (resp->data.auth.unix_username &&
283             strlen(resp->data.auth.unix_username)) {
284                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
285                                              &i->blobs,
286                                              "unix_username",
287                                              0,
288                                              (uint8_t *)resp->data.auth.unix_username,
289                                              strlen(resp->data.auth.unix_username)+1);
290                 BAIL_ON_WBC_ERROR(wbc_status);
291         }
292
293         *_i = i;
294         i = NULL;
295 done:
296         if (!WBC_ERROR_IS_OK(wbc_status) && i) {
297                 wbcFreeMemory(i->blobs);
298         }
299
300         talloc_free(i);
301         return wbc_status;
302 }
303
304 /* Authenticate with more detailed information */
305 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
306                              struct wbcAuthUserInfo **info,
307                              struct wbcAuthErrorInfo **error)
308 {
309         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
310         int cmd = 0;
311         struct winbindd_request request;
312         struct winbindd_response response;
313
314         ZERO_STRUCT(request);
315         ZERO_STRUCT(response);
316
317         if (error) {
318                 *error = NULL;
319         }
320
321         if (!params) {
322                 wbc_status = WBC_ERR_INVALID_PARAM;
323                 BAIL_ON_WBC_ERROR(wbc_status);
324         }
325
326         if (!params->account_name) {
327                 wbc_status = WBC_ERR_INVALID_PARAM;
328                 BAIL_ON_WBC_ERROR(wbc_status);
329         }
330
331         /* Initialize request */
332
333         switch (params->level) {
334         case WBC_AUTH_USER_LEVEL_PLAIN:
335                 cmd = WINBINDD_PAM_AUTH;
336                 request.flags = WBFLAG_PAM_INFO3_TEXT |
337                                 WBFLAG_PAM_USER_SESSION_KEY |
338                                 WBFLAG_PAM_LMKEY;
339
340                 if (!params->password.plaintext) {
341                         wbc_status = WBC_ERR_INVALID_PARAM;
342                         BAIL_ON_WBC_ERROR(wbc_status);
343                 }
344
345                 if (params->domain_name && params->domain_name[0]) {
346                         /* We need to get the winbind separator :-( */
347                         struct winbindd_response sep_response;
348
349                         ZERO_STRUCT(sep_response);
350
351                         wbc_status = wbcRequestResponse(WINBINDD_INFO,
352                                                         NULL, &sep_response);
353                         BAIL_ON_WBC_ERROR(wbc_status);
354
355                         snprintf(request.data.auth.user,
356                                  sizeof(request.data.auth.user)-1,
357                                  "%s%c%s",
358                                  params->domain_name,
359                                  sep_response.data.info.winbind_separator,
360                                  params->account_name);
361                 } else {
362                         strncpy(request.data.auth.user,
363                                 params->account_name,
364                                 sizeof(request.data.auth.user)-1);
365                 }
366
367                 strncpy(request.data.auth.pass,
368                         params->password.plaintext,
369                         sizeof(request.data.auth.pass)-1);
370                 break;
371
372         case WBC_AUTH_USER_LEVEL_HASH:
373                 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
374                 BAIL_ON_WBC_ERROR(wbc_status);
375                 break;
376
377         case WBC_AUTH_USER_LEVEL_RESPONSE:
378                 cmd = WINBINDD_PAM_AUTH_CRAP;
379                 request.flags = WBFLAG_PAM_INFO3_TEXT |
380                                 WBFLAG_PAM_USER_SESSION_KEY |
381                                 WBFLAG_PAM_LMKEY;
382
383                 if (params->password.response.lm_length &&
384                     !params->password.response.lm_data) {
385                         wbc_status = WBC_ERR_INVALID_PARAM;
386                         BAIL_ON_WBC_ERROR(wbc_status);
387                 }
388                 if (params->password.response.lm_length == 0 &&
389                     params->password.response.lm_data) {
390                         wbc_status = WBC_ERR_INVALID_PARAM;
391                         BAIL_ON_WBC_ERROR(wbc_status);
392                 }
393
394                 if (params->password.response.nt_length &&
395                     !params->password.response.nt_data) {
396                         wbc_status = WBC_ERR_INVALID_PARAM;
397                         BAIL_ON_WBC_ERROR(wbc_status);
398                 }
399                 if (params->password.response.nt_length == 0&&
400                     params->password.response.nt_data) {
401                         wbc_status = WBC_ERR_INVALID_PARAM;
402                         BAIL_ON_WBC_ERROR(wbc_status);
403                 }
404
405                 strncpy(request.data.auth_crap.user,
406                         params->account_name,
407                         sizeof(request.data.auth_crap.user)-1);
408                 if (params->domain_name) {
409                         strncpy(request.data.auth_crap.domain,
410                                 params->domain_name,
411                                 sizeof(request.data.auth_crap.domain)-1);
412                 }
413                 if (params->workstation_name) {
414                         strncpy(request.data.auth_crap.workstation,
415                                 params->workstation_name,
416                                 sizeof(request.data.auth_crap.workstation)-1);
417                 }
418
419                 request.data.auth_crap.logon_parameters =
420                                 params->parameter_control;
421
422                 memcpy(request.data.auth_crap.chal,
423                        params->password.response.challenge,
424                        sizeof(request.data.auth_crap.chal));
425
426                 request.data.auth_crap.lm_resp_len =
427                                 MIN(params->password.response.lm_length,
428                                     sizeof(request.data.auth_crap.lm_resp));
429                 if (params->password.response.lm_data) {
430                         memcpy(request.data.auth_crap.lm_resp,
431                                params->password.response.lm_data,
432                                request.data.auth_crap.lm_resp_len);
433                 }
434                 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
435                 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
436                         request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
437                         request.extra_len = params->password.response.nt_length;
438                         request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len);
439                         if (request.extra_data.data == NULL) {
440                                 wbc_status = WBC_ERR_NO_MEMORY;
441                                 BAIL_ON_WBC_ERROR(wbc_status);
442                         }
443                         memcpy(request.extra_data.data,
444                                params->password.response.nt_data,
445                                request.data.auth_crap.nt_resp_len);
446                 } else if (params->password.response.nt_data) {
447                         memcpy(request.data.auth_crap.nt_resp,
448                                params->password.response.nt_data,
449                                request.data.auth_crap.nt_resp_len);
450                 }
451                 break;
452         default:
453                 break;
454         }
455
456         if (cmd == 0) {
457                 wbc_status = WBC_ERR_INVALID_PARAM;
458                 BAIL_ON_WBC_ERROR(wbc_status);
459         }
460
461         if (params->flags) {
462                 request.flags |= params->flags;
463         }
464
465         wbc_status = wbcRequestResponse(cmd,
466                                         &request,
467                                         &response);
468         if (response.data.auth.nt_status != 0) {
469                 if (error) {
470                         wbc_status = wbc_create_error_info(NULL,
471                                                            &response,
472                                                            error);
473                         BAIL_ON_WBC_ERROR(wbc_status);
474                 }
475
476                 wbc_status = WBC_ERR_AUTH_ERROR;
477                 BAIL_ON_WBC_ERROR(wbc_status);
478         }
479         BAIL_ON_WBC_ERROR(wbc_status);
480
481         if (info) {
482                 wbc_status = wbc_create_auth_info(NULL,
483                                                   &response,
484                                                   info);
485                 BAIL_ON_WBC_ERROR(wbc_status);
486         }
487
488 done:
489         if (response.extra_data.data)
490                 free(response.extra_data.data);
491
492         talloc_free(request.extra_data.data);
493
494         return wbc_status;
495 }
496
497 /* Trigger a verification of the trust credentials of a specific domain */
498 wbcErr wbcCheckTrustCredentials(const char *domain,
499                                 struct wbcAuthErrorInfo **error)
500 {
501         struct winbindd_request request;
502         struct winbindd_response response;
503         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
504
505         ZERO_STRUCT(request);
506         ZERO_STRUCT(response);
507
508         if (domain) {
509                 strncpy(request.domain_name, domain,
510                         sizeof(request.domain_name)-1);
511         }
512
513         /* Send request */
514
515         wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC,
516                                         &request,
517                                         &response);
518         if (response.data.auth.nt_status != 0) {
519                 if (error) {
520                         wbc_status = wbc_create_error_info(NULL,
521                                                            &response,
522                                                            error);
523                         BAIL_ON_WBC_ERROR(wbc_status);
524                 }
525
526                 wbc_status = WBC_ERR_AUTH_ERROR;
527                 BAIL_ON_WBC_ERROR(wbc_status);
528         }
529         BAIL_ON_WBC_ERROR(wbc_status);
530
531  done:
532         return wbc_status;
533 }
534
535 /* Trigger a change of the trust credentials for a specific domain */
536 wbcErr wbcChangeTrustCredentials(const char *domain,
537                                  struct wbcAuthErrorInfo **error)
538 {
539         struct winbindd_request request;
540         struct winbindd_response response;
541         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
542
543         ZERO_STRUCT(request);
544         ZERO_STRUCT(response);
545
546         if (domain) {
547                 strncpy(request.domain_name, domain,
548                         sizeof(request.domain_name)-1);
549         }
550
551         /* Send request */
552
553         wbc_status = wbcRequestResponse(WINBINDD_CHANGE_MACHACC,
554                                         &request,
555                                         &response);
556         if (response.data.auth.nt_status != 0) {
557                 if (error) {
558                         wbc_status = wbc_create_error_info(NULL,
559                                                            &response,
560                                                            error);
561                         BAIL_ON_WBC_ERROR(wbc_status);
562                 }
563
564                 wbc_status = WBC_ERR_AUTH_ERROR;
565                 BAIL_ON_WBC_ERROR(wbc_status);
566         }
567         BAIL_ON_WBC_ERROR(wbc_status);
568
569  done:
570         return wbc_status;
571 }
572
573 /* Trigger an extended logoff notification to Winbind for a specific user */
574 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
575                        struct wbcAuthErrorInfo **error)
576 {
577         struct winbindd_request request;
578         struct winbindd_response response;
579         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
580         int i;
581
582         /* validate input */
583
584         if (!params || !params->username) {
585                 wbc_status = WBC_ERR_INVALID_PARAM;
586                 BAIL_ON_WBC_ERROR(wbc_status);
587         }
588
589         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
590                 wbc_status = WBC_ERR_INVALID_PARAM;
591                 BAIL_ON_WBC_ERROR(wbc_status);
592         }
593         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
594                 wbc_status = WBC_ERR_INVALID_PARAM;
595                 BAIL_ON_WBC_ERROR(wbc_status);
596         }
597
598         ZERO_STRUCT(request);
599         ZERO_STRUCT(response);
600
601         strncpy(request.data.logoff.user, params->username,
602                 sizeof(request.data.logoff.user)-1);
603
604         for (i=0; i<params->num_blobs; i++) {
605
606                 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
607                         if (params->blobs[i].blob.data) {
608                                 strncpy(request.data.logoff.krb5ccname,
609                                         (const char *)params->blobs[i].blob.data,
610                                         sizeof(request.data.logoff.krb5ccname) - 1);
611                         }
612                         continue;
613                 }
614
615                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
616                         if (params->blobs[i].blob.data) {
617                                 memcpy(&request.data.logoff.uid,
618                                         params->blobs[i].blob.data,
619                                         MIN(params->blobs[i].blob.length,
620                                             sizeof(request.data.logoff.uid)));
621                         }
622                         continue;
623                 }
624
625                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
626                         if (params->blobs[i].blob.data) {
627                                 memcpy(&request.flags,
628                                         params->blobs[i].blob.data,
629                                         MIN(params->blobs[i].blob.length,
630                                             sizeof(request.flags)));
631                         }
632                         continue;
633                 }
634         }
635
636         /* Send request */
637
638         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
639                                         &request,
640                                         &response);
641
642         /* Take the response above and return it to the caller */
643         if (response.data.auth.nt_status != 0) {
644                 if (error) {
645                         wbc_status = wbc_create_error_info(NULL,
646                                                            &response,
647                                                            error);
648                         BAIL_ON_WBC_ERROR(wbc_status);
649                 }
650
651                 wbc_status = WBC_ERR_AUTH_ERROR;
652                 BAIL_ON_WBC_ERROR(wbc_status);
653         }
654         BAIL_ON_WBC_ERROR(wbc_status);
655
656  done:
657         return wbc_status;
658 }
659
660 /* Trigger a logoff notification to Winbind for a specific user */
661 wbcErr wbcLogoffUser(const char *username,
662                      uid_t uid,
663                      const char *ccfilename)
664 {
665         struct winbindd_request request;
666         struct winbindd_response response;
667         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
668
669         /* validate input */
670
671         if (!username) {
672                 wbc_status = WBC_ERR_INVALID_PARAM;
673                 BAIL_ON_WBC_ERROR(wbc_status);
674         }
675
676         ZERO_STRUCT(request);
677         ZERO_STRUCT(response);
678
679         strncpy(request.data.logoff.user, username,
680                 sizeof(request.data.logoff.user)-1);
681         request.data.logoff.uid = uid;
682
683         if (ccfilename) {
684                 strncpy(request.data.logoff.krb5ccname, ccfilename,
685                         sizeof(request.data.logoff.krb5ccname)-1);
686         }
687
688         /* Send request */
689
690         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
691                                         &request,
692                                         &response);
693
694         /* Take the response above and return it to the caller */
695
696  done:
697         return wbc_status;
698 }
699
700 /* Change a password for a user with more detailed information upon failure */
701 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
702                                struct wbcAuthErrorInfo **error,
703                                enum wbcPasswordChangeRejectReason *reject_reason,
704                                struct wbcUserPasswordPolicyInfo **policy)
705 {
706         struct winbindd_request request;
707         struct winbindd_response response;
708         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
709         int cmd = 0;
710
711         /* validate input */
712
713         if (!params->account_name) {
714                 wbc_status = WBC_ERR_INVALID_PARAM;
715                 BAIL_ON_WBC_ERROR(wbc_status);
716         }
717
718         if (error) {
719                 *error = NULL;
720         }
721
722         if (policy) {
723                 *policy = NULL;
724         }
725
726         if (reject_reason) {
727                 *reject_reason = -1;
728         }
729
730         ZERO_STRUCT(request);
731         ZERO_STRUCT(response);
732
733         switch (params->level) {
734         case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
735                 cmd = WINBINDD_PAM_CHAUTHTOK;
736
737                 if (!params->account_name) {
738                         wbc_status = WBC_ERR_INVALID_PARAM;
739                         BAIL_ON_WBC_ERROR(wbc_status);
740                 }
741
742                 strncpy(request.data.chauthtok.user, params->account_name,
743                         sizeof(request.data.chauthtok.user) - 1);
744
745                 if (params->old_password.plaintext) {
746                         strncpy(request.data.chauthtok.oldpass,
747                                 params->old_password.plaintext,
748                                 sizeof(request.data.chauthtok.oldpass) - 1);
749                 }
750
751                 if (params->new_password.plaintext) {
752                         strncpy(request.data.chauthtok.newpass,
753                                 params->new_password.plaintext,
754                                 sizeof(request.data.chauthtok.newpass) - 1);
755                 }
756                 break;
757
758         case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
759                 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
760
761                 if (!params->account_name || !params->domain_name) {
762                         wbc_status = WBC_ERR_INVALID_PARAM;
763                         BAIL_ON_WBC_ERROR(wbc_status);
764                 }
765
766                 if (params->old_password.response.old_lm_hash_enc_length &&
767                     !params->old_password.response.old_lm_hash_enc_data) {
768                         wbc_status = WBC_ERR_INVALID_PARAM;
769                         BAIL_ON_WBC_ERROR(wbc_status);
770                 }
771
772                 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
773                     params->old_password.response.old_lm_hash_enc_data) {
774                         wbc_status = WBC_ERR_INVALID_PARAM;
775                         BAIL_ON_WBC_ERROR(wbc_status);
776                 }
777
778                 if (params->old_password.response.old_nt_hash_enc_length &&
779                     !params->old_password.response.old_nt_hash_enc_data) {
780                         wbc_status = WBC_ERR_INVALID_PARAM;
781                         BAIL_ON_WBC_ERROR(wbc_status);
782                 }
783
784                 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
785                     params->old_password.response.old_nt_hash_enc_data) {
786                         wbc_status = WBC_ERR_INVALID_PARAM;
787                         BAIL_ON_WBC_ERROR(wbc_status);
788                 }
789
790                 if (params->new_password.response.lm_length &&
791                     !params->new_password.response.lm_data) {
792                         wbc_status = WBC_ERR_INVALID_PARAM;
793                         BAIL_ON_WBC_ERROR(wbc_status);
794                 }
795
796                 if (params->new_password.response.lm_length == 0 &&
797                     params->new_password.response.lm_data) {
798                         wbc_status = WBC_ERR_INVALID_PARAM;
799                         BAIL_ON_WBC_ERROR(wbc_status);
800                 }
801
802                 if (params->new_password.response.nt_length &&
803                     !params->new_password.response.nt_data) {
804                         wbc_status = WBC_ERR_INVALID_PARAM;
805                         BAIL_ON_WBC_ERROR(wbc_status);
806                 }
807
808                 if (params->new_password.response.nt_length == 0 &&
809                     params->new_password.response.nt_data) {
810                         wbc_status = WBC_ERR_INVALID_PARAM;
811                         BAIL_ON_WBC_ERROR(wbc_status);
812                 }
813
814                 strncpy(request.data.chng_pswd_auth_crap.user,
815                         params->account_name,
816                         sizeof(request.data.chng_pswd_auth_crap.user) - 1);
817
818                 strncpy(request.data.chng_pswd_auth_crap.domain,
819                         params->domain_name,
820                         sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
821
822                 if (params->new_password.response.nt_data) {
823                         memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
824                                params->new_password.response.nt_data,
825                                request.data.chng_pswd_auth_crap.new_nt_pswd_len);
826                         request.data.chng_pswd_auth_crap.new_nt_pswd_len =
827                                 params->new_password.response.nt_length;
828                 }
829
830                 if (params->new_password.response.lm_data) {
831                         memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
832                                params->new_password.response.lm_data,
833                                request.data.chng_pswd_auth_crap.new_lm_pswd_len);
834                         request.data.chng_pswd_auth_crap.new_lm_pswd_len =
835                                 params->new_password.response.lm_length;
836                 }
837
838                 if (params->old_password.response.old_nt_hash_enc_data) {
839                         memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
840                                params->old_password.response.old_nt_hash_enc_data,
841                                request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
842                         request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
843                                 params->old_password.response.old_nt_hash_enc_length;
844                 }
845
846                 if (params->old_password.response.old_lm_hash_enc_data) {
847                         memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
848                                params->old_password.response.old_lm_hash_enc_data,
849                                request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
850                         request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
851                                 params->old_password.response.old_lm_hash_enc_length;
852                 }
853
854                 break;
855         default:
856                 wbc_status = WBC_ERR_INVALID_PARAM;
857                 BAIL_ON_WBC_ERROR(wbc_status);
858                 break;
859         }
860
861         /* Send request */
862
863         wbc_status = wbcRequestResponse(cmd,
864                                         &request,
865                                         &response);
866         if (WBC_ERROR_IS_OK(wbc_status)) {
867                 goto done;
868         }
869
870         /* Take the response above and return it to the caller */
871
872         if (response.data.auth.nt_status != 0) {
873                 if (error) {
874                         wbc_status = wbc_create_error_info(NULL,
875                                                            &response,
876                                                            error);
877                         BAIL_ON_WBC_ERROR(wbc_status);
878                 }
879
880         }
881
882         if (policy) {
883                 wbc_status = wbc_create_password_policy_info(NULL,
884                                                              &response,
885                                                              policy);
886                 BAIL_ON_WBC_ERROR(wbc_status);
887         }
888
889         if (reject_reason) {
890                 *reject_reason = response.data.auth.reject_reason;
891         }
892
893         wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
894         BAIL_ON_WBC_ERROR(wbc_status);
895
896  done:
897         return wbc_status;
898 }
899
900 /* Change a password for a user */
901 wbcErr wbcChangeUserPassword(const char *username,
902                              const char *old_password,
903                              const char *new_password)
904 {
905         wbcErr wbc_status = WBC_ERR_SUCCESS;
906         struct wbcChangePasswordParams params;
907
908         ZERO_STRUCT(params);
909
910         params.account_name             = username;
911         params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
912         params.old_password.plaintext   = old_password;
913         params.new_password.plaintext   = new_password;
914
915         wbc_status = wbcChangeUserPasswordEx(&params,
916                                              NULL,
917                                              NULL,
918                                              NULL);
919         BAIL_ON_WBC_ERROR(wbc_status);
920
921 done:
922         return wbc_status;
923 }
924
925 /* Logon a User */
926 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
927                     struct wbcLogonUserInfo **info,
928                     struct wbcAuthErrorInfo **error,
929                     struct wbcUserPasswordPolicyInfo **policy)
930 {
931         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
932         int cmd = 0;
933         struct winbindd_request request;
934         struct winbindd_response response;
935         uint32_t i;
936
937         ZERO_STRUCT(request);
938         ZERO_STRUCT(response);
939
940         if (info) {
941                 *info = NULL;
942         }
943         if (error) {
944                 *error = NULL;
945         }
946         if (policy) {
947                 *policy = NULL;
948         }
949
950         if (!params) {
951                 wbc_status = WBC_ERR_INVALID_PARAM;
952                 BAIL_ON_WBC_ERROR(wbc_status);
953         }
954
955         if (!params->username) {
956                 wbc_status = WBC_ERR_INVALID_PARAM;
957                 BAIL_ON_WBC_ERROR(wbc_status);
958         }
959
960         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
961                 wbc_status = WBC_ERR_INVALID_PARAM;
962                 BAIL_ON_WBC_ERROR(wbc_status);
963         }
964         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
965                 wbc_status = WBC_ERR_INVALID_PARAM;
966                 BAIL_ON_WBC_ERROR(wbc_status);
967         }
968
969         /* Initialize request */
970
971         cmd = WINBINDD_PAM_AUTH;
972         request.flags = WBFLAG_PAM_INFO3_TEXT |
973                         WBFLAG_PAM_USER_SESSION_KEY |
974                         WBFLAG_PAM_LMKEY;
975
976         if (!params->password) {
977                 wbc_status = WBC_ERR_INVALID_PARAM;
978                 BAIL_ON_WBC_ERROR(wbc_status);
979         }
980
981         strncpy(request.data.auth.user,
982                 params->username,
983                 sizeof(request.data.auth.user)-1);
984
985         strncpy(request.data.auth.pass,
986                 params->password,
987                 sizeof(request.data.auth.pass)-1);
988
989         for (i=0; i<params->num_blobs; i++) {
990
991                 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
992                         if (params->blobs[i].blob.data) {
993                                 strncpy(request.data.auth.krb5_cc_type,
994                                         (const char *)params->blobs[i].blob.data,
995                                         sizeof(request.data.auth.krb5_cc_type) - 1);
996                         }
997                         continue;
998                 }
999
1000                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1001                         if (params->blobs[i].blob.data) {
1002                                 memcpy(&request.data.auth.uid,
1003                                         params->blobs[i].blob.data,
1004                                         MIN(sizeof(request.data.auth.uid),
1005                                             params->blobs[i].blob.length));
1006                         }
1007                         continue;
1008                 }
1009
1010                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1011                         if (params->blobs[i].blob.data) {
1012                                 uint32_t flags;
1013                                 memcpy(&flags,
1014                                         params->blobs[i].blob.data,
1015                                         MIN(sizeof(flags),
1016                                             params->blobs[i].blob.length));
1017                                 request.flags |= flags;
1018                         }
1019                         continue;
1020                 }
1021
1022                 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1023                         if (params->blobs[i].blob.data &&
1024                             params->blobs[i].blob.data[0] > 0) {
1025                                 strncpy(request.data.auth.require_membership_of_sid,
1026                                         (const char *)params->blobs[i].blob.data,
1027                                         sizeof(request.data.auth.require_membership_of_sid) - 1);
1028                         }
1029                         continue;
1030                 }
1031         }
1032
1033         wbc_status = wbcRequestResponse(cmd,
1034                                         &request,
1035                                         &response);
1036
1037         if (response.data.auth.nt_status != 0) {
1038                 if (error) {
1039                         wbc_status = wbc_create_error_info(NULL,
1040                                                            &response,
1041                                                            error);
1042                         BAIL_ON_WBC_ERROR(wbc_status);
1043                 }
1044
1045                 wbc_status = WBC_ERR_AUTH_ERROR;
1046                 BAIL_ON_WBC_ERROR(wbc_status);
1047         }
1048         BAIL_ON_WBC_ERROR(wbc_status);
1049
1050         if (info) {
1051                 wbc_status = wbc_create_logon_info(NULL,
1052                                                    &response,
1053                                                    info);
1054                 BAIL_ON_WBC_ERROR(wbc_status);
1055         }
1056
1057         if (policy) {
1058                 wbc_status = wbc_create_password_policy_info(NULL,
1059                                                              &response,
1060                                                              policy);
1061                 BAIL_ON_WBC_ERROR(wbc_status);
1062         }
1063
1064 done:
1065         if (response.extra_data.data)
1066                 free(response.extra_data.data);
1067
1068         return wbc_status;
1069 }
1070
1071 /* Authenticate a user with cached credentials */
1072 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1073                           struct wbcCredentialCacheInfo **info,
1074                           struct wbcAuthErrorInfo **error)
1075 {
1076         return WBC_ERR_NOT_IMPLEMENTED;
1077 }