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