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