libwbclient: add wbcLogonUser().
[Samba/bb.git] / source / nsswitch / libwbclient / wbc_pam.c
blob713ba2e65b5baed7849a74f0a9fc1a76658acaef
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Guenther Deschner 2008
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.
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.
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/>.
23 /* Required Headers */
25 #include "libwbclient.h"
27 /** @brief Authenticate a username/password pair
29 * @param username Name of user to authenticate
30 * @param password Clear text password os user
32 * @return #wbcErr
33 **/
35 wbcErr wbcAuthenticateUser(const char *username,
36 const char *password)
38 wbcErr wbc_status = WBC_ERR_SUCCESS;
39 struct wbcAuthUserParams params;
41 ZERO_STRUCT(params);
43 params.account_name = username;
44 params.level = WBC_AUTH_USER_LEVEL_PLAIN;
45 params.password.plaintext = password;
47 wbc_status = wbcAuthenticateUserEx(&params, NULL, NULL);
48 BAIL_ON_WBC_ERROR(wbc_status);
50 done:
51 return wbc_status;
54 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
55 const struct winbindd_response *resp,
56 struct wbcAuthUserInfo **_i)
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;
65 i = talloc(mem_ctx, struct wbcAuthUserInfo);
66 BAIL_ON_PTR_ERROR(i, wbc_status);
68 i->user_flags = resp->data.auth.info3.user_flgs;
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;
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));
87 i->logon_count = resp->data.auth.info3.logon_count;
88 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
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;
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);
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;
112 i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
113 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
115 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
116 &domain_sid);
117 BAIL_ON_WBC_ERROR(wbc_status);
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); \
127 (s).attributes = a; \
128 } while (0)
130 sn = 0;
131 _SID_COMPOSE(i->sids[sn], domain_sid,
132 resp->data.auth.info3.user_rid,
134 sn++;
135 _SID_COMPOSE(i->sids[sn], domain_sid,
136 resp->data.auth.info3.group_rid,
138 sn++;
140 p = (char *)resp->extra_data.data;
141 if (!p) {
142 wbc_status = WBC_ERR_INVALID_RESPONSE;
143 BAIL_ON_WBC_ERROR(wbc_status);
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);
156 e[0] = '\0';
157 p = &e[1];
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);
165 _SID_COMPOSE(i->sids[sn], domain_sid,
166 rid, attrs);
167 sn++;
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);
180 e[0] = '\0';
181 p = &e[1];
183 e = strchr(s, ':');
184 if (!e) {
185 wbc_status = WBC_ERR_INVALID_RESPONSE;
186 BAIL_ON_WBC_ERROR(wbc_status);
188 e[0] = '\0';
189 a = &e[1];
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);
198 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
199 BAIL_ON_WBC_ERROR(wbc_status);
201 i->sids[sn].attributes = attrs;
202 sn++;
205 i->num_sids = sn;
207 *_i = i;
208 i = NULL;
209 done:
210 talloc_free(i);
211 return wbc_status;
214 static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
215 const struct winbindd_response *resp,
216 struct wbcAuthErrorInfo **_e)
218 wbcErr wbc_status = WBC_ERR_SUCCESS;
219 struct wbcAuthErrorInfo *e;
221 e = talloc(mem_ctx, struct wbcAuthErrorInfo);
222 BAIL_ON_PTR_ERROR(e, wbc_status);
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);
229 e->display_string = talloc_strdup(e, resp->data.auth.error_string);
230 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
232 *_e = e;
233 e = NULL;
235 done:
236 talloc_free(e);
237 return wbc_status;
240 static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx,
241 const struct winbindd_response *resp,
242 struct wbcUserPasswordPolicyInfo **_i)
244 wbcErr wbc_status = WBC_ERR_SUCCESS;
245 struct wbcUserPasswordPolicyInfo *i;
247 i = talloc(mem_ctx, struct wbcUserPasswordPolicyInfo);
248 BAIL_ON_PTR_ERROR(i, wbc_status);
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;
256 *_i = i;
257 i = NULL;
259 done:
260 talloc_free(i);
261 return wbc_status;
264 static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx,
265 const struct winbindd_response *resp,
266 struct wbcLogonUserInfo **_i)
268 wbcErr wbc_status = WBC_ERR_SUCCESS;
269 struct wbcLogonUserInfo *i;
271 i = talloc_zero(mem_ctx, struct wbcLogonUserInfo);
272 BAIL_ON_PTR_ERROR(i, wbc_status);
274 wbc_status = wbc_create_auth_info(i, resp, &i->info);
275 BAIL_ON_WBC_ERROR(wbc_status);
277 if (resp->data.auth.krb5ccname) {
278 wbc_status = wbcAddNamedBlob(&i->num_blobs,
279 &i->blobs,
280 "krb5ccname",
282 (uint8_t *)resp->data.auth.krb5ccname,
283 strlen(resp->data.auth.krb5ccname)+1);
284 BAIL_ON_WBC_ERROR(wbc_status);
287 if (resp->data.auth.unix_username) {
288 wbc_status = wbcAddNamedBlob(&i->num_blobs,
289 &i->blobs,
290 "unix_username",
292 (uint8_t *)resp->data.auth.unix_username,
293 strlen(resp->data.auth.unix_username)+1);
294 BAIL_ON_WBC_ERROR(wbc_status);
297 *_i = i;
298 i = NULL;
299 done:
300 if (!WBC_ERROR_IS_OK(wbc_status) && i) {
301 wbcFreeMemory(i->blobs);
304 talloc_free(i);
305 return wbc_status;
308 /** @brief Authenticate with more detailed information
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
315 * @return #wbcErr
318 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
319 struct wbcAuthUserInfo **info,
320 struct wbcAuthErrorInfo **error)
322 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
323 int cmd = 0;
324 struct winbindd_request request;
325 struct winbindd_response response;
327 ZERO_STRUCT(request);
328 ZERO_STRUCT(response);
330 if (error) {
331 *error = NULL;
334 if (!params) {
335 wbc_status = WBC_ERR_INVALID_PARAM;
336 BAIL_ON_WBC_ERROR(wbc_status);
339 if (!params->account_name) {
340 wbc_status = WBC_ERR_INVALID_PARAM;
341 BAIL_ON_WBC_ERROR(wbc_status);
344 /* Initialize request */
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;
353 if (!params->password.plaintext) {
354 wbc_status = WBC_ERR_INVALID_PARAM;
355 BAIL_ON_WBC_ERROR(wbc_status);
358 if (params->domain_name && params->domain_name[0]) {
359 /* We need to get the winbind separator :-( */
360 struct winbindd_response sep_response;
362 ZERO_STRUCT(sep_response);
364 wbc_status = wbcRequestResponse(WINBINDD_INFO,
365 NULL, &sep_response);
366 BAIL_ON_WBC_ERROR(wbc_status);
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);
380 strncpy(request.data.auth.pass,
381 params->password.plaintext,
382 sizeof(request.data.auth.pass)-1);
383 break;
385 case WBC_AUTH_USER_LEVEL_HASH:
386 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
387 BAIL_ON_WBC_ERROR(wbc_status);
388 break;
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;
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);
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);
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);
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);
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);
426 if (params->workstation_name) {
427 strncpy(request.data.auth_crap.workstation,
428 params->workstation_name,
429 sizeof(request.data.auth_crap.workstation)-1);
432 request.data.auth_crap.logon_parameters =
433 params->parameter_control;
435 memcpy(request.data.auth_crap.chal,
436 params->password.response.challenge,
437 sizeof(request.data.auth_crap.chal));
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);
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);
455 break;
456 default:
457 break;
460 if (cmd == 0) {
461 wbc_status = WBC_ERR_INVALID_PARAM;
462 BAIL_ON_WBC_ERROR(wbc_status);
465 if (params->flags) {
466 request.flags |= params->flags;
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);
480 wbc_status = WBC_ERR_AUTH_ERROR;
481 BAIL_ON_WBC_ERROR(wbc_status);
483 BAIL_ON_WBC_ERROR(wbc_status);
485 if (info) {
486 wbc_status = wbc_create_auth_info(NULL,
487 &response,
488 info);
489 BAIL_ON_WBC_ERROR(wbc_status);
492 done:
493 if (response.extra_data.data)
494 free(response.extra_data.data);
496 return wbc_status;
499 /** @brief Trigger a verification of the trust credentials of a specific domain
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
506 * @return #wbcErr
509 wbcErr wbcCheckTrustCredentials(const char *domain,
510 struct wbcAuthErrorInfo **error)
512 struct winbindd_request request;
513 struct winbindd_response response;
514 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
516 if (domain) {
518 * the current protocol doesn't support
519 * specifying a domain
521 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
522 BAIL_ON_WBC_ERROR(wbc_status);
525 ZERO_STRUCT(request);
526 ZERO_STRUCT(response);
528 /* Send request */
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);
541 wbc_status = WBC_ERR_AUTH_ERROR;
542 BAIL_ON_WBC_ERROR(wbc_status);
544 BAIL_ON_WBC_ERROR(wbc_status);
546 done:
547 return wbc_status;
550 /** @brief Trigger an extended logoff notification to Winbind for a specific user
552 * @param params A wbcLogoffUserParams structure
553 * @param error User output details on error
555 * @return #wbcErr
559 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
560 struct wbcAuthErrorInfo **error)
562 struct winbindd_request request;
563 struct winbindd_response response;
564 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
565 int i;
567 /* validate input */
569 if (!params || !params->username) {
570 wbc_status = WBC_ERR_INVALID_PARAM;
571 BAIL_ON_WBC_ERROR(wbc_status);
574 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
575 wbc_status = WBC_ERR_INVALID_PARAM;
576 BAIL_ON_WBC_ERROR(wbc_status);
578 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
579 wbc_status = WBC_ERR_INVALID_PARAM;
580 BAIL_ON_WBC_ERROR(wbc_status);
583 ZERO_STRUCT(request);
584 ZERO_STRUCT(response);
586 strncpy(request.data.logoff.user, params->username,
587 sizeof(request.data.logoff.user)-1);
589 for (i=0; i<params->num_blobs; i++) {
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);
597 continue;
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)));
607 continue;
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)));
617 continue;
621 /* Send request */
623 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
624 &request,
625 &response);
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);
636 wbc_status = WBC_ERR_AUTH_ERROR;
637 BAIL_ON_WBC_ERROR(wbc_status);
639 BAIL_ON_WBC_ERROR(wbc_status);
641 done:
642 return wbc_status;
645 /** @brief Trigger a logoff notification to Winbind for a specific user
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
653 * @return #wbcErr
657 wbcErr wbcLogoffUser(const char *username,
658 uid_t uid,
659 const char *ccfilename)
661 struct winbindd_request request;
662 struct winbindd_response response;
663 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
665 /* validate input */
667 if (!username) {
668 wbc_status = WBC_ERR_INVALID_PARAM;
669 BAIL_ON_WBC_ERROR(wbc_status);
672 ZERO_STRUCT(request);
673 ZERO_STRUCT(response);
675 strncpy(request.data.logoff.user, username,
676 sizeof(request.data.logoff.user)-1);
677 request.data.logoff.uid = uid;
679 if (ccfilename) {
680 strncpy(request.data.logoff.krb5ccname, ccfilename,
681 sizeof(request.data.logoff.krb5ccname)-1);
684 /* Send request */
686 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
687 &request,
688 &response);
690 /* Take the response above and return it to the caller */
692 done:
693 return wbc_status;
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
703 * @return #wbcErr
706 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
707 struct wbcAuthErrorInfo **error,
708 enum wbcPasswordChangeRejectReason *reject_reason,
709 struct wbcUserPasswordPolicyInfo **policy)
711 struct winbindd_request request;
712 struct winbindd_response response;
713 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
714 int cmd = 0;
716 /* validate input */
718 if (!params->account_name) {
719 wbc_status = WBC_ERR_INVALID_PARAM;
720 BAIL_ON_WBC_ERROR(wbc_status);
723 if (error) {
724 *error = NULL;
727 if (policy) {
728 *policy = NULL;
731 if (reject_reason) {
732 *reject_reason = -1;
735 ZERO_STRUCT(request);
736 ZERO_STRUCT(response);
738 switch (params->level) {
739 case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
740 cmd = WINBINDD_PAM_CHAUTHTOK;
742 if (!params->account_name) {
743 wbc_status = WBC_ERR_INVALID_PARAM;
744 BAIL_ON_WBC_ERROR(wbc_status);
747 strncpy(request.data.chauthtok.user, params->account_name,
748 sizeof(request.data.chauthtok.user) - 1);
750 if (params->old_password.plaintext) {
751 strncpy(request.data.chauthtok.oldpass,
752 params->old_password.plaintext,
753 sizeof(request.data.chauthtok.oldpass) - 1);
756 if (params->new_password.plaintext) {
757 strncpy(request.data.chauthtok.newpass,
758 params->new_password.plaintext,
759 sizeof(request.data.chauthtok.newpass) - 1);
761 break;
763 case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
764 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
766 if (!params->account_name || !params->domain_name) {
767 wbc_status = WBC_ERR_INVALID_PARAM;
768 BAIL_ON_WBC_ERROR(wbc_status);
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);
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);
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);
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);
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);
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);
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);
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);
819 strncpy(request.data.chng_pswd_auth_crap.user,
820 params->account_name,
821 sizeof(request.data.chng_pswd_auth_crap.user) - 1);
823 strncpy(request.data.chng_pswd_auth_crap.domain,
824 params->domain_name,
825 sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
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;
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;
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;
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;
859 break;
860 default:
861 wbc_status = WBC_ERR_INVALID_PARAM;
862 BAIL_ON_WBC_ERROR(wbc_status);
863 break;
866 if (cmd == 0) {
867 wbc_status = WBC_ERR_INVALID_PARAM;
868 BAIL_ON_WBC_ERROR(wbc_status);
871 /* Send request */
873 wbc_status = wbcRequestResponse(cmd,
874 &request,
875 &response);
876 if (WBC_ERROR_IS_OK(wbc_status)) {
877 goto done;
880 /* Take the response above and return it to the caller */
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);
892 if (policy) {
893 wbc_status = wbc_create_password_policy_info(NULL,
894 &response,
895 policy);
896 BAIL_ON_WBC_ERROR(wbc_status);
899 if (reject_reason) {
900 *reject_reason = response.data.auth.reject_reason;
903 wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
904 BAIL_ON_WBC_ERROR(wbc_status);
906 done:
907 return wbc_status;
910 /** @brief Change a password for a user
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
916 * @return #wbcErr
919 wbcErr wbcChangeUserPassword(const char *username,
920 const char *old_password,
921 const char *new_password)
923 wbcErr wbc_status = WBC_ERR_SUCCESS;
924 struct wbcChangePasswordParams params;
926 ZERO_STRUCT(params);
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;
933 wbc_status = wbcChangeUserPasswordEx(&params,
934 NULL,
935 NULL,
936 NULL);
937 BAIL_ON_WBC_ERROR(wbc_status);
939 done:
940 return wbc_status;
943 /** @brief Logon a User
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
950 * @return #wbcErr
954 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
955 struct wbcLogonUserInfo **info,
956 struct wbcAuthErrorInfo **error,
957 struct wbcUserPasswordPolicyInfo **policy)
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;
965 ZERO_STRUCT(request);
966 ZERO_STRUCT(response);
968 if (info) {
969 *info = NULL;
971 if (error) {
972 *error = NULL;
974 if (policy) {
975 *policy = NULL;
978 if (!params) {
979 wbc_status = WBC_ERR_INVALID_PARAM;
980 BAIL_ON_WBC_ERROR(wbc_status);
983 if (!params->username) {
984 wbc_status = WBC_ERR_INVALID_PARAM;
985 BAIL_ON_WBC_ERROR(wbc_status);
988 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
989 wbc_status = WBC_ERR_INVALID_PARAM;
990 BAIL_ON_WBC_ERROR(wbc_status);
992 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
993 wbc_status = WBC_ERR_INVALID_PARAM;
994 BAIL_ON_WBC_ERROR(wbc_status);
997 /* Initialize request */
999 cmd = WINBINDD_PAM_AUTH;
1000 request.flags = WBFLAG_PAM_INFO3_TEXT |
1001 WBFLAG_PAM_USER_SESSION_KEY |
1002 WBFLAG_PAM_LMKEY;
1004 if (!params->password) {
1005 wbc_status = WBC_ERR_INVALID_PARAM;
1006 BAIL_ON_WBC_ERROR(wbc_status);
1009 strncpy(request.data.auth.user,
1010 params->username,
1011 sizeof(request.data.auth.user)-1);
1013 strncpy(request.data.auth.pass,
1014 params->password,
1015 sizeof(request.data.auth.pass)-1);
1017 for (i=0; i<params->num_blobs; i++) {
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);
1025 continue;
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));
1035 continue;
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;
1047 continue;
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);
1057 continue;
1061 wbc_status = wbcRequestResponse(cmd,
1062 &request,
1063 &response);
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);
1073 wbc_status = WBC_ERR_AUTH_ERROR;
1074 BAIL_ON_WBC_ERROR(wbc_status);
1076 BAIL_ON_WBC_ERROR(wbc_status);
1078 if (info) {
1079 wbc_status = wbc_create_logon_info(NULL,
1080 &response,
1081 info);
1082 BAIL_ON_WBC_ERROR(wbc_status);
1085 if (policy) {
1086 wbc_status = wbc_create_password_policy_info(NULL,
1087 &response,
1088 policy);
1089 BAIL_ON_WBC_ERROR(wbc_status);
1092 done:
1093 if (response.extra_data.data)
1094 free(response.extra_data.data);
1096 return wbc_status;