root/nsswitch/libwbclient/wbc_pam.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wbcAuthenticateUser
  2. wbc_create_auth_info
  3. wbc_create_error_info
  4. wbc_create_password_policy_info
  5. wbc_create_logon_info
  6. wbcAuthenticateUserEx
  7. wbcCheckTrustCredentials
  8. wbcLogoffUserEx
  9. wbcLogoffUser
  10. wbcChangeUserPasswordEx
  11. wbcChangeUserPassword
  12. wbcLogonUser
  13. wbcCredentialCache

   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,
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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                 if (params->password.response.lm_data) {
 427                         memcpy(request.data.auth_crap.lm_resp,
 428                                params->password.response.lm_data,
 429                                request.data.auth_crap.lm_resp_len);
 430                 }
 431                 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
 432                 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
 433                         request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
 434                         request.extra_len = params->password.response.nt_length;
 435                         request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len);
 436                         if (request.extra_data.data == NULL) {
 437                                 wbc_status = WBC_ERR_NO_MEMORY;
 438                                 BAIL_ON_WBC_ERROR(wbc_status);
 439                         }
 440                         memcpy(request.extra_data.data,
 441                                params->password.response.nt_data,
 442                                request.data.auth_crap.nt_resp_len);
 443                 } else if (params->password.response.nt_data) {
 444                         memcpy(request.data.auth_crap.nt_resp,
 445                                params->password.response.nt_data,
 446                                request.data.auth_crap.nt_resp_len);
 447                 }
 448                 break;
 449         default:
 450                 break;
 451         }
 452 
 453         if (cmd == 0) {
 454                 wbc_status = WBC_ERR_INVALID_PARAM;
 455                 BAIL_ON_WBC_ERROR(wbc_status);
 456         }
 457 
 458         if (params->flags) {
 459                 request.flags |= params->flags;
 460         }
 461 
 462         wbc_status = wbcRequestResponse(cmd,
 463                                         &request,
 464                                         &response);
 465         if (response.data.auth.nt_status != 0) {
 466                 if (error) {
 467                         wbc_status = wbc_create_error_info(NULL,
 468                                                            &response,
 469                                                            error);
 470                         BAIL_ON_WBC_ERROR(wbc_status);
 471                 }
 472 
 473                 wbc_status = WBC_ERR_AUTH_ERROR;
 474                 BAIL_ON_WBC_ERROR(wbc_status);
 475         }
 476         BAIL_ON_WBC_ERROR(wbc_status);
 477 
 478         if (info) {
 479                 wbc_status = wbc_create_auth_info(NULL,
 480                                                   &response,
 481                                                   info);
 482                 BAIL_ON_WBC_ERROR(wbc_status);
 483         }
 484 
 485 done:
 486         if (response.extra_data.data)
 487                 free(response.extra_data.data);
 488 
 489         talloc_free(request.extra_data.data);
 490 
 491         return wbc_status;
 492 }
 493 
 494 /* Trigger a verification of the trust credentials of a specific domain */
 495 wbcErr wbcCheckTrustCredentials(const char *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 496                                 struct wbcAuthErrorInfo **error)
 497 {
 498         struct winbindd_request request;
 499         struct winbindd_response response;
 500         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 501 
 502         if (domain) {
 503                 /*
 504                  * the current protocol doesn't support
 505                  * specifying a domain
 506                  */
 507                 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
 508                 BAIL_ON_WBC_ERROR(wbc_status);
 509         }
 510 
 511         ZERO_STRUCT(request);
 512         ZERO_STRUCT(response);
 513 
 514         /* Send request */
 515 
 516         wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC,
 517                                         &request,
 518                                         &response);
 519         if (response.data.auth.nt_status != 0) {
 520                 if (error) {
 521                         wbc_status = wbc_create_error_info(NULL,
 522                                                            &response,
 523                                                            error);
 524                         BAIL_ON_WBC_ERROR(wbc_status);
 525                 }
 526 
 527                 wbc_status = WBC_ERR_AUTH_ERROR;
 528                 BAIL_ON_WBC_ERROR(wbc_status);
 529         }
 530         BAIL_ON_WBC_ERROR(wbc_status);
 531 
 532  done:
 533         return wbc_status;
 534 }
 535 
 536 /* Trigger an extended logoff notification to Winbind for a specific user */
 537 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
     /* [<][>][^][v][top][bottom][index][help] */
 538                        struct wbcAuthErrorInfo **error)
 539 {
 540         struct winbindd_request request;
 541         struct winbindd_response response;
 542         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 543         int i;
 544 
 545         /* validate input */
 546 
 547         if (!params || !params->username) {
 548                 wbc_status = WBC_ERR_INVALID_PARAM;
 549                 BAIL_ON_WBC_ERROR(wbc_status);
 550         }
 551 
 552         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
 553                 wbc_status = WBC_ERR_INVALID_PARAM;
 554                 BAIL_ON_WBC_ERROR(wbc_status);
 555         }
 556         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
 557                 wbc_status = WBC_ERR_INVALID_PARAM;
 558                 BAIL_ON_WBC_ERROR(wbc_status);
 559         }
 560 
 561         ZERO_STRUCT(request);
 562         ZERO_STRUCT(response);
 563 
 564         strncpy(request.data.logoff.user, params->username,
 565                 sizeof(request.data.logoff.user)-1);
 566 
 567         for (i=0; i<params->num_blobs; i++) {
 568 
 569                 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
 570                         if (params->blobs[i].blob.data) {
 571                                 strncpy(request.data.logoff.krb5ccname,
 572                                         (const char *)params->blobs[i].blob.data,
 573                                         sizeof(request.data.logoff.krb5ccname) - 1);
 574                         }
 575                         continue;
 576                 }
 577 
 578                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
 579                         if (params->blobs[i].blob.data) {
 580                                 memcpy(&request.data.logoff.uid,
 581                                         params->blobs[i].blob.data,
 582                                         MIN(params->blobs[i].blob.length,
 583                                             sizeof(request.data.logoff.uid)));
 584                         }
 585                         continue;
 586                 }
 587 
 588                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
 589                         if (params->blobs[i].blob.data) {
 590                                 memcpy(&request.flags,
 591                                         params->blobs[i].blob.data,
 592                                         MIN(params->blobs[i].blob.length,
 593                                             sizeof(request.flags)));
 594                         }
 595                         continue;
 596                 }
 597         }
 598 
 599         /* Send request */
 600 
 601         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
 602                                         &request,
 603                                         &response);
 604 
 605         /* Take the response above and return it to the caller */
 606         if (response.data.auth.nt_status != 0) {
 607                 if (error) {
 608                         wbc_status = wbc_create_error_info(NULL,
 609                                                            &response,
 610                                                            error);
 611                         BAIL_ON_WBC_ERROR(wbc_status);
 612                 }
 613 
 614                 wbc_status = WBC_ERR_AUTH_ERROR;
 615                 BAIL_ON_WBC_ERROR(wbc_status);
 616         }
 617         BAIL_ON_WBC_ERROR(wbc_status);
 618 
 619  done:
 620         return wbc_status;
 621 }
 622 
 623 /* Trigger a logoff notification to Winbind for a specific user */
 624 wbcErr wbcLogoffUser(const char *username,
     /* [<][>][^][v][top][bottom][index][help] */
 625                      uid_t uid,
 626                      const char *ccfilename)
 627 {
 628         struct winbindd_request request;
 629         struct winbindd_response response;
 630         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 631 
 632         /* validate input */
 633 
 634         if (!username) {
 635                 wbc_status = WBC_ERR_INVALID_PARAM;
 636                 BAIL_ON_WBC_ERROR(wbc_status);
 637         }
 638 
 639         ZERO_STRUCT(request);
 640         ZERO_STRUCT(response);
 641 
 642         strncpy(request.data.logoff.user, username,
 643                 sizeof(request.data.logoff.user)-1);
 644         request.data.logoff.uid = uid;
 645 
 646         if (ccfilename) {
 647                 strncpy(request.data.logoff.krb5ccname, ccfilename,
 648                         sizeof(request.data.logoff.krb5ccname)-1);
 649         }
 650 
 651         /* Send request */
 652 
 653         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
 654                                         &request,
 655                                         &response);
 656 
 657         /* Take the response above and return it to the caller */
 658 
 659  done:
 660         return wbc_status;
 661 }
 662 
 663 /* Change a password for a user with more detailed information upon failure */
 664 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
     /* [<][>][^][v][top][bottom][index][help] */
 665                                struct wbcAuthErrorInfo **error,
 666                                enum wbcPasswordChangeRejectReason *reject_reason,
 667                                struct wbcUserPasswordPolicyInfo **policy)
 668 {
 669         struct winbindd_request request;
 670         struct winbindd_response response;
 671         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 672         int cmd = 0;
 673 
 674         /* validate input */
 675 
 676         if (!params->account_name) {
 677                 wbc_status = WBC_ERR_INVALID_PARAM;
 678                 BAIL_ON_WBC_ERROR(wbc_status);
 679         }
 680 
 681         if (error) {
 682                 *error = NULL;
 683         }
 684 
 685         if (policy) {
 686                 *policy = NULL;
 687         }
 688 
 689         if (reject_reason) {
 690                 *reject_reason = -1;
 691         }
 692 
 693         ZERO_STRUCT(request);
 694         ZERO_STRUCT(response);
 695 
 696         switch (params->level) {
 697         case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
 698                 cmd = WINBINDD_PAM_CHAUTHTOK;
 699 
 700                 if (!params->account_name) {
 701                         wbc_status = WBC_ERR_INVALID_PARAM;
 702                         BAIL_ON_WBC_ERROR(wbc_status);
 703                 }
 704 
 705                 strncpy(request.data.chauthtok.user, params->account_name,
 706                         sizeof(request.data.chauthtok.user) - 1);
 707 
 708                 if (params->old_password.plaintext) {
 709                         strncpy(request.data.chauthtok.oldpass,
 710                                 params->old_password.plaintext,
 711                                 sizeof(request.data.chauthtok.oldpass) - 1);
 712                 }
 713 
 714                 if (params->new_password.plaintext) {
 715                         strncpy(request.data.chauthtok.newpass,
 716                                 params->new_password.plaintext,
 717                                 sizeof(request.data.chauthtok.newpass) - 1);
 718                 }
 719                 break;
 720 
 721         case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
 722                 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
 723 
 724                 if (!params->account_name || !params->domain_name) {
 725                         wbc_status = WBC_ERR_INVALID_PARAM;
 726                         BAIL_ON_WBC_ERROR(wbc_status);
 727                 }
 728 
 729                 if (params->old_password.response.old_lm_hash_enc_length &&
 730                     !params->old_password.response.old_lm_hash_enc_data) {
 731                         wbc_status = WBC_ERR_INVALID_PARAM;
 732                         BAIL_ON_WBC_ERROR(wbc_status);
 733                 }
 734 
 735                 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
 736                     params->old_password.response.old_lm_hash_enc_data) {
 737                         wbc_status = WBC_ERR_INVALID_PARAM;
 738                         BAIL_ON_WBC_ERROR(wbc_status);
 739                 }
 740 
 741                 if (params->old_password.response.old_nt_hash_enc_length &&
 742                     !params->old_password.response.old_nt_hash_enc_data) {
 743                         wbc_status = WBC_ERR_INVALID_PARAM;
 744                         BAIL_ON_WBC_ERROR(wbc_status);
 745                 }
 746 
 747                 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
 748                     params->old_password.response.old_nt_hash_enc_data) {
 749                         wbc_status = WBC_ERR_INVALID_PARAM;
 750                         BAIL_ON_WBC_ERROR(wbc_status);
 751                 }
 752 
 753                 if (params->new_password.response.lm_length &&
 754                     !params->new_password.response.lm_data) {
 755                         wbc_status = WBC_ERR_INVALID_PARAM;
 756                         BAIL_ON_WBC_ERROR(wbc_status);
 757                 }
 758 
 759                 if (params->new_password.response.lm_length == 0 &&
 760                     params->new_password.response.lm_data) {
 761                         wbc_status = WBC_ERR_INVALID_PARAM;
 762                         BAIL_ON_WBC_ERROR(wbc_status);
 763                 }
 764 
 765                 if (params->new_password.response.nt_length &&
 766                     !params->new_password.response.nt_data) {
 767                         wbc_status = WBC_ERR_INVALID_PARAM;
 768                         BAIL_ON_WBC_ERROR(wbc_status);
 769                 }
 770 
 771                 if (params->new_password.response.nt_length == 0 &&
 772                     params->new_password.response.nt_data) {
 773                         wbc_status = WBC_ERR_INVALID_PARAM;
 774                         BAIL_ON_WBC_ERROR(wbc_status);
 775                 }
 776 
 777                 strncpy(request.data.chng_pswd_auth_crap.user,
 778                         params->account_name,
 779                         sizeof(request.data.chng_pswd_auth_crap.user) - 1);
 780 
 781                 strncpy(request.data.chng_pswd_auth_crap.domain,
 782                         params->domain_name,
 783                         sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
 784 
 785                 if (params->new_password.response.nt_data) {
 786                         memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
 787                                params->new_password.response.nt_data,
 788                                request.data.chng_pswd_auth_crap.new_nt_pswd_len);
 789                         request.data.chng_pswd_auth_crap.new_nt_pswd_len =
 790                                 params->new_password.response.nt_length;
 791                 }
 792 
 793                 if (params->new_password.response.lm_data) {
 794                         memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
 795                                params->new_password.response.lm_data,
 796                                request.data.chng_pswd_auth_crap.new_lm_pswd_len);
 797                         request.data.chng_pswd_auth_crap.new_lm_pswd_len =
 798                                 params->new_password.response.lm_length;
 799                 }
 800 
 801                 if (params->old_password.response.old_nt_hash_enc_data) {
 802                         memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
 803                                params->old_password.response.old_nt_hash_enc_data,
 804                                request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
 805                         request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
 806                                 params->old_password.response.old_nt_hash_enc_length;
 807                 }
 808 
 809                 if (params->old_password.response.old_lm_hash_enc_data) {
 810                         memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
 811                                params->old_password.response.old_lm_hash_enc_data,
 812                                request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
 813                         request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
 814                                 params->old_password.response.old_lm_hash_enc_length;
 815                 }
 816 
 817                 break;
 818         default:
 819                 wbc_status = WBC_ERR_INVALID_PARAM;
 820                 BAIL_ON_WBC_ERROR(wbc_status);
 821                 break;
 822         }
 823 
 824         /* Send request */
 825 
 826         wbc_status = wbcRequestResponse(cmd,
 827                                         &request,
 828                                         &response);
 829         if (WBC_ERROR_IS_OK(wbc_status)) {
 830                 goto done;
 831         }
 832 
 833         /* Take the response above and return it to the caller */
 834 
 835         if (response.data.auth.nt_status != 0) {
 836                 if (error) {
 837                         wbc_status = wbc_create_error_info(NULL,
 838                                                            &response,
 839                                                            error);
 840                         BAIL_ON_WBC_ERROR(wbc_status);
 841                 }
 842 
 843         }
 844 
 845         if (policy) {
 846                 wbc_status = wbc_create_password_policy_info(NULL,
 847                                                              &response,
 848                                                              policy);
 849                 BAIL_ON_WBC_ERROR(wbc_status);
 850         }
 851 
 852         if (reject_reason) {
 853                 *reject_reason = response.data.auth.reject_reason;
 854         }
 855 
 856         wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
 857         BAIL_ON_WBC_ERROR(wbc_status);
 858 
 859  done:
 860         return wbc_status;
 861 }
 862 
 863 /* Change a password for a user */
 864 wbcErr wbcChangeUserPassword(const char *username,
     /* [<][>][^][v][top][bottom][index][help] */
 865                              const char *old_password,
 866                              const char *new_password)
 867 {
 868         wbcErr wbc_status = WBC_ERR_SUCCESS;
 869         struct wbcChangePasswordParams params;
 870 
 871         ZERO_STRUCT(params);
 872 
 873         params.account_name             = username;
 874         params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
 875         params.old_password.plaintext   = old_password;
 876         params.new_password.plaintext   = new_password;
 877 
 878         wbc_status = wbcChangeUserPasswordEx(&params,
 879                                              NULL,
 880                                              NULL,
 881                                              NULL);
 882         BAIL_ON_WBC_ERROR(wbc_status);
 883 
 884 done:
 885         return wbc_status;
 886 }
 887 
 888 /* Logon a User */
 889 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
     /* [<][>][^][v][top][bottom][index][help] */
 890                     struct wbcLogonUserInfo **info,
 891                     struct wbcAuthErrorInfo **error,
 892                     struct wbcUserPasswordPolicyInfo **policy)
 893 {
 894         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
 895         int cmd = 0;
 896         struct winbindd_request request;
 897         struct winbindd_response response;
 898         uint32_t i;
 899 
 900         ZERO_STRUCT(request);
 901         ZERO_STRUCT(response);
 902 
 903         if (info) {
 904                 *info = NULL;
 905         }
 906         if (error) {
 907                 *error = NULL;
 908         }
 909         if (policy) {
 910                 *policy = NULL;
 911         }
 912 
 913         if (!params) {
 914                 wbc_status = WBC_ERR_INVALID_PARAM;
 915                 BAIL_ON_WBC_ERROR(wbc_status);
 916         }
 917 
 918         if (!params->username) {
 919                 wbc_status = WBC_ERR_INVALID_PARAM;
 920                 BAIL_ON_WBC_ERROR(wbc_status);
 921         }
 922 
 923         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
 924                 wbc_status = WBC_ERR_INVALID_PARAM;
 925                 BAIL_ON_WBC_ERROR(wbc_status);
 926         }
 927         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
 928                 wbc_status = WBC_ERR_INVALID_PARAM;
 929                 BAIL_ON_WBC_ERROR(wbc_status);
 930         }
 931 
 932         /* Initialize request */
 933 
 934         cmd = WINBINDD_PAM_AUTH;
 935         request.flags = WBFLAG_PAM_INFO3_TEXT |
 936                         WBFLAG_PAM_USER_SESSION_KEY |
 937                         WBFLAG_PAM_LMKEY;
 938 
 939         if (!params->password) {
 940                 wbc_status = WBC_ERR_INVALID_PARAM;
 941                 BAIL_ON_WBC_ERROR(wbc_status);
 942         }
 943 
 944         strncpy(request.data.auth.user,
 945                 params->username,
 946                 sizeof(request.data.auth.user)-1);
 947 
 948         strncpy(request.data.auth.pass,
 949                 params->password,
 950                 sizeof(request.data.auth.pass)-1);
 951 
 952         for (i=0; i<params->num_blobs; i++) {
 953 
 954                 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
 955                         if (params->blobs[i].blob.data) {
 956                                 strncpy(request.data.auth.krb5_cc_type,
 957                                         (const char *)params->blobs[i].blob.data,
 958                                         sizeof(request.data.auth.krb5_cc_type) - 1);
 959                         }
 960                         continue;
 961                 }
 962 
 963                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
 964                         if (params->blobs[i].blob.data) {
 965                                 memcpy(&request.data.auth.uid,
 966                                         params->blobs[i].blob.data,
 967                                         MIN(sizeof(request.data.auth.uid),
 968                                             params->blobs[i].blob.length));
 969                         }
 970                         continue;
 971                 }
 972 
 973                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
 974                         if (params->blobs[i].blob.data) {
 975                                 uint32_t flags;
 976                                 memcpy(&flags,
 977                                         params->blobs[i].blob.data,
 978                                         MIN(sizeof(flags),
 979                                             params->blobs[i].blob.length));
 980                                 request.flags |= flags;
 981                         }
 982                         continue;
 983                 }
 984 
 985                 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
 986                         if (params->blobs[i].blob.data &&
 987                             params->blobs[i].blob.data[0] > 0) {
 988                                 strncpy(request.data.auth.require_membership_of_sid,
 989                                         (const char *)params->blobs[i].blob.data,
 990                                         sizeof(request.data.auth.require_membership_of_sid) - 1);
 991                         }
 992                         continue;
 993                 }
 994         }
 995 
 996         wbc_status = wbcRequestResponse(cmd,
 997                                         &request,
 998                                         &response);
 999 
1000         if (response.data.auth.nt_status != 0) {
1001                 if (error) {
1002                         wbc_status = wbc_create_error_info(NULL,
1003                                                            &response,
1004                                                            error);
1005                         BAIL_ON_WBC_ERROR(wbc_status);
1006                 }
1007 
1008                 wbc_status = WBC_ERR_AUTH_ERROR;
1009                 BAIL_ON_WBC_ERROR(wbc_status);
1010         }
1011         BAIL_ON_WBC_ERROR(wbc_status);
1012 
1013         if (info) {
1014                 wbc_status = wbc_create_logon_info(NULL,
1015                                                    &response,
1016                                                    info);
1017                 BAIL_ON_WBC_ERROR(wbc_status);
1018         }
1019 
1020         if (policy) {
1021                 wbc_status = wbc_create_password_policy_info(NULL,
1022                                                              &response,
1023                                                              policy);
1024                 BAIL_ON_WBC_ERROR(wbc_status);
1025         }
1026 
1027 done:
1028         if (response.extra_data.data)
1029                 free(response.extra_data.data);
1030 
1031         return wbc_status;
1032 }
1033 
1034 /* Authenticate a user with cached credentials */
1035 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
     /* [<][>][^][v][top][bottom][index][help] */
1036                           struct wbcCredentialCacheInfo **info,
1037                           struct wbcAuthErrorInfo **error)
1038 {
1039         return WBC_ERR_NOT_IMPLEMENTED;
1040 }

/* [<][>][^][v][top][bottom][index][help] */