1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include <fcntl.h> 18 #include <stdarg.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/stat.h> 23 #include <syslog.h> 24 #include <unistd.h> 25 26 #include <security/pam_ext.h> 27 #include <security/pam_modules.h> 28 #include <security/pam_modutil.h> 29 30 #include <openssl/evp.h> 31 #include <openssl/hmac.h> 32 #include <openssl/rand.h> 33 34 /* 35 * This module is intended to save password of special group user 36 * 37 */ 38 39 #define MAX_SPEC_GRP_PASS_LENGTH 20 40 #define MAX_SPEC_GRP_USER_LENGTH 16 41 #define MAX_KEY_SIZE 8 42 #define DEFAULT_SPEC_PASS_FILE "/etc/ipmi_pass" 43 #define META_PASSWD_SIG "=OPENBMC=" 44 45 /* 46 * Meta data struct for storing the encrypted password file 47 * Note: Followed by this structure, the real data of hash, iv, encrypted data 48 * with pad and mac are stored. 49 * Decrypted data will hold user name & password for every new line with format 50 * like <user name>:<password>\n 51 */ 52 typedef struct metapassstruct { 53 char signature[10]; 54 unsigned char reseved[2]; 55 size_t hashsize; 56 size_t ivsize; 57 size_t datasize; 58 size_t padsize; 59 size_t macsize; 60 } metapassstruct; 61 62 /** 63 * @brief to acquire lock for atomic operation 64 * Internally uses lckpwdf to acquire the lock. Tries to acquire the lock 65 * using lckpwdf() in interval of 1ms, with maximum of 100 attempts. 66 * 67 * @return PAM_SUCCESS for success / PAM_AUTHTOK_LOCK_BUSY for failure 68 */ 69 int lock_pwdf(void) 70 { 71 int i; 72 int retval; 73 74 i = 0; 75 while ((retval = lckpwdf()) != 0 && i < 100) { 76 usleep(1000); 77 i++; 78 } 79 if (retval != 0) { 80 return PAM_AUTHTOK_LOCK_BUSY; 81 } 82 return PAM_SUCCESS; 83 } 84 85 /** 86 * @brief unlock the acquired lock 87 * Internally uses ulckpwdf to release the lock 88 */ 89 void unlock_pwdf(void) 90 { 91 ulckpwdf(); 92 } 93 94 /** 95 * @brief to get argument value of option 96 * Function to get the value of argument options. 97 * 98 * @param[in] pamh - pam handle 99 * @param[in] option - argument option to which value has to returned 100 * @param[in] argc - argument count 101 * @param[in] argv - array of arguments 102 */ 103 static const char *get_option(const pam_handle_t *pamh, const char *option, 104 int argc, const char **argv) 105 { 106 int i; 107 size_t len; 108 109 len = strlen(option); 110 111 for (i = 0; i < argc; ++i) { 112 if (strncmp(option, argv[i], len) == 0) { 113 if (argv[i][len] == '=') { 114 return &argv[i][len + 1]; 115 } 116 } 117 } 118 return NULL; 119 } 120 121 /** 122 * @brief encrypt or decrypt function 123 * Function which will do the encryption or decryption of the data. 124 * 125 * @param[in] pamh - pam handle. 126 * @param[in] isencrypt - encrypt or decrypt option. 127 * @param[in] cipher - EVP_CIPHER to be used 128 * @param[in] key - key which has to be used in EVP_CIPHER api's. 129 * @param[in] keylen - Length of the key. 130 * @param[in] iv - Initialization vector data, used along with key 131 * @param[in] ivlen - Length of IV. 132 * @param[in] inbytes - buffer which has to be encrypted or decrypted. 133 * @param[in] inbyteslen - length of input buffer. 134 * @param[in] outbytes - buffer to store decrypted or encrypted data. 135 * @param[in] outbyteslen - length of output buffer 136 * @param[in/out] mac - checksum to cross verify. Will be verified for decrypt 137 * and returns for encrypt. 138 * @param[in/out] maclen - length of checksum 139 * @return - 0 for success -1 for failures. 140 */ 141 int encrypt_decrypt_data(const pam_handle_t *pamh, int isencrypt, 142 const EVP_CIPHER *cipher, const char *key, 143 size_t keylen, const char *iv, size_t ivlen, 144 const char *inbytes, size_t inbyteslen, char *outbytes, 145 size_t *outbyteslen, char *mac, size_t *maclen) 146 { 147 EVP_CIPHER_CTX *ctx; 148 const EVP_MD *digest; 149 size_t outEVPlen = 0; 150 int retval = 0; 151 size_t outlen = 0; 152 153 if (cipher == NULL || key == NULL || iv == NULL || inbytes == NULL || 154 outbytes == NULL || mac == NULL || inbyteslen == 0 || 155 EVP_CIPHER_key_length(cipher) > keylen || 156 EVP_CIPHER_iv_length(cipher) > ivlen) { 157 pam_syslog(pamh, LOG_DEBUG, "Invalid inputs"); 158 return -1; 159 } 160 161 digest = EVP_sha256(); 162 if (!isencrypt) { 163 char calmac[EVP_MAX_MD_SIZE]; 164 size_t calmaclen = 0; 165 // calculate MAC for the encrypted message. 166 if (NULL == HMAC(digest, key, keylen, inbytes, inbyteslen, 167 calmac, &calmaclen)) { 168 pam_syslog(pamh, LOG_DEBUG, 169 "Failed to verify authentication %d", 170 retval); 171 return -1; 172 } 173 if (!((calmaclen == *maclen) && 174 (memcmp(calmac, mac, calmaclen) == 0))) { 175 pam_syslog(pamh, LOG_DEBUG, 176 "Authenticated message doesn't match %d, %d", 177 calmaclen, *maclen); 178 return -1; 179 } 180 } 181 182 ctx = EVP_CIPHER_CTX_new(); 183 EVP_CIPHER_CTX_set_padding(ctx, 1); 184 185 // Set key & IV 186 retval = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, isencrypt); 187 if (!retval) { 188 pam_syslog(pamh, LOG_DEBUG, "EVP_CipherInit_ex failed with %d", 189 retval); 190 EVP_CIPHER_CTX_free(ctx); 191 return -1; 192 } 193 if ((retval = EVP_CipherUpdate(ctx, outbytes + outlen, &outEVPlen, 194 inbytes, inbyteslen))) { 195 outlen += outEVPlen; 196 if ((retval = 197 EVP_CipherFinal(ctx, outbytes + outlen, &outEVPlen))) { 198 outlen += outEVPlen; 199 *outbyteslen = outlen; 200 } else { 201 pam_syslog(pamh, LOG_DEBUG, 202 "EVP_CipherFinal returns with %d", retval); 203 EVP_CIPHER_CTX_free(ctx); 204 return -1; 205 } 206 } else { 207 pam_syslog(pamh, LOG_DEBUG, "EVP_CipherUpdate returns with %d", 208 retval); 209 EVP_CIPHER_CTX_free(ctx); 210 return -1; 211 } 212 EVP_CIPHER_CTX_free(ctx); 213 214 if (isencrypt) { 215 // Create MAC for the encrypted message. 216 if (NULL == HMAC(digest, key, keylen, outbytes, *outbyteslen, 217 mac, maclen)) { 218 pam_syslog(pamh, LOG_DEBUG, 219 "Failed to create authentication %d", 220 retval); 221 return -1; 222 } 223 } 224 return 0; 225 } 226 227 /** 228 * @brief get temporary file handle 229 * Function to get the temporary file handle, created using mkstemp 230 * 231 * @param[in] pamh - pam handle. 232 * @param[in/out] tempfilename - tempfilename, which will be used in mkstemp. 233 * @return - FILE handle for success. NULL for failure 234 */ 235 FILE *get_temp_file_handle(const pam_handle_t *pamh, char *const tempfilename) 236 { 237 FILE *tempfile = NULL; 238 int fd; 239 int oldmask = umask(077); 240 fd = mkstemp(tempfilename); 241 if (fd == -1) { 242 pam_syslog(pamh, LOG_DEBUG, "Error in creating temp file"); 243 umask(oldmask); 244 return NULL; 245 } 246 pam_syslog(pamh, LOG_DEBUG, "Temporary file name is %s", tempfilename); 247 248 tempfile = fdopen(fd, "w"); 249 umask(oldmask); 250 return tempfile; 251 } 252 253 /** 254 * @brief updates special password file 255 * Function to update the special password file. Stores the password against 256 * username in encrypted form along with meta data 257 * 258 * @param[in] pamh - pam handle. 259 * @param[in] keyfilename - file name where key seed is stored. 260 * @param[in] filename - special password file name 261 * @param[in] forwho - name of the user 262 * @param[in] towhat - password that has to stored in encrypted form 263 * @return - PAM_SUCCESS for success or PAM_AUTHTOK_ERR for failure 264 */ 265 int update_pass_special_file(const pam_handle_t *pamh, const char *keyfilename, 266 const char *filename, const char *forwho, 267 const char *towhat) 268 { 269 struct stat st; 270 FILE *pwfile = NULL, *opwfile = NULL, *keyfile = NULL; 271 int err = 0, wroteentry = 0; 272 char tempfilename[1024]; 273 size_t forwholen = strlen(forwho); 274 size_t towhatlen = strlen(towhat); 275 char keybuff[MAX_KEY_SIZE] = {0}; 276 size_t keybuffsize = sizeof(keybuff); 277 278 const EVP_CIPHER *cipher = EVP_aes_128_cbc(); 279 const EVP_MD *digest = EVP_sha256(); 280 281 char *linebuff = NULL, *opwfilebuff = NULL, *opwptext = NULL; 282 size_t opwptextlen = 0, opwfilesize = 0; 283 metapassstruct *opwmp = NULL; 284 285 char *pwptext = NULL, *pwctext = NULL; 286 size_t pwctextlen = 0, pwptextlen = 0, maclen = 0; 287 size_t writtensize = 0, keylen = 0; 288 metapassstruct pwmp = {META_PASSWD_SIG, {0, 0}, .0, 0, 0, 0, 0}; 289 char mac[EVP_MAX_MD_SIZE] = {0}; 290 unsigned char key[EVP_MAX_KEY_LENGTH]; 291 char iv[EVP_CIPHER_iv_length(cipher)]; 292 char hash[EVP_MD_block_size(digest)]; 293 294 // Following steps are performed in this function. 295 // Step 1: Create a temporary file - always update temporary file, and 296 // then swap it with original one, only if everything succeded at the 297 // end. Step 2: If file already exists, read the old file and decrypt it 298 // in buffer Step 3: Copy user/password pair from old buffer to new 299 // buffer, and update, if the user already exists with the new password 300 // Step 4: Encrypt the new buffer and write it to the temp file created 301 // at Step 1. 302 // Step 5. rename the temporary file name as special password file. 303 304 // verify the tempfilename buffer is enough to hold 305 // filename_XXXXXX (+1 for null). 306 if (strlen(filename) > 307 (sizeof(tempfilename) - strlen("__XXXXXX") - 1)) { 308 pam_syslog(pamh, LOG_DEBUG, "Not enough buffer, bailing out"); 309 return PAM_AUTHTOK_ERR; 310 } 311 // Fetch the key from key file name. 312 keyfile = fopen(keyfilename, "r"); 313 if (keyfile == NULL) { 314 pam_syslog(pamh, LOG_DEBUG, "Unable to open key file %s", 315 keyfilename); 316 return PAM_AUTHTOK_ERR; 317 } 318 if (fread(keybuff, 1, keybuffsize, keyfile) != keybuffsize) { 319 pam_syslog(pamh, LOG_DEBUG, "Key file read failed"); 320 fclose(keyfile); 321 return PAM_AUTHTOK_ERR; 322 } 323 fclose(keyfile); 324 325 // Step 1: Try to create a temporary file, in which all the update will 326 // happen then it will be renamed to the original file. This is done to 327 // have atomic operation. 328 snprintf(tempfilename, sizeof(tempfilename), "%s__XXXXXX", filename); 329 pwfile = get_temp_file_handle(pamh, tempfilename); 330 if (pwfile == NULL) { 331 err = 1; 332 goto done; 333 } 334 335 // Update temporary file stat by reading the special password file 336 opwfile = fopen(filename, "r"); 337 if (opwfile != NULL) { 338 if (fstat(fileno(opwfile), &st) == -1) { 339 fclose(opwfile); 340 fclose(pwfile); 341 err = 1; 342 goto done; 343 } 344 } else { // Create with this settings if file is not present. 345 memset(&st, 0, sizeof(st)); 346 } 347 // Override the file permission with S_IWUSR | S_IRUSR 348 st.st_mode = S_IWUSR | S_IRUSR; 349 if ((fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) || 350 (fchmod(fileno(pwfile), st.st_mode) == -1)) { 351 if (opwfile != NULL) { 352 fclose(opwfile); 353 } 354 fclose(pwfile); 355 err = 1; 356 goto done; 357 } 358 opwfilesize = st.st_size; 359 360 // Step 2: Read existing special password file and decrypt the data. 361 if (opwfilesize) { 362 opwfilebuff = malloc(opwfilesize); 363 if (opwfilebuff == NULL) { 364 fclose(opwfile); 365 fclose(pwfile); 366 err = 1; 367 goto done; 368 } 369 370 if (fread(opwfilebuff, 1, opwfilesize, opwfile)) { 371 opwmp = (metapassstruct *)opwfilebuff; 372 opwptext = malloc(opwmp->datasize + opwmp->padsize); 373 if (opwptext == NULL) { 374 free(opwfilebuff); 375 fclose(opwfile); 376 fclose(pwfile); 377 err = 1; 378 goto done; 379 } 380 // User & password pairs are mapped as <user 381 // name>:<password>\n. Add +3 for special chars ':', 382 // '\n' and '\0'. 383 pwptextlen = opwmp->datasize + forwholen + towhatlen + 384 3 + EVP_CIPHER_block_size(cipher); 385 pwptext = malloc(pwptextlen); 386 if (pwptext == NULL) { 387 free(opwptext); 388 free(opwfilebuff); 389 fclose(opwfile); 390 fclose(pwfile); 391 err = 1; 392 goto done; 393 } 394 395 // First get the hashed key to decrypt 396 HMAC(digest, keybuff, keybuffsize, 397 opwfilebuff + sizeof(*opwmp), opwmp->hashsize, key, 398 &keylen); 399 400 // Skip decryption if there is no data 401 if (opwmp->datasize != 0) { 402 // Do the decryption 403 if (encrypt_decrypt_data( 404 pamh, 0, cipher, key, keylen, 405 opwfilebuff + sizeof(*opwmp) + 406 opwmp->hashsize, 407 opwmp->ivsize, 408 opwfilebuff + sizeof(*opwmp) + 409 opwmp->hashsize + opwmp->ivsize, 410 opwmp->datasize + opwmp->padsize, 411 opwptext, &opwptextlen, 412 opwfilebuff + sizeof(*opwmp) + 413 opwmp->hashsize + opwmp->ivsize + 414 opwmp->datasize + opwmp->padsize, 415 &opwmp->macsize) != 0) { 416 pam_syslog(pamh, LOG_DEBUG, 417 "Decryption failed"); 418 free(pwptext); 419 free(opwptext); 420 free(opwfilebuff); 421 fclose(opwfile); 422 fclose(pwfile); 423 err = 1; 424 goto done; 425 } 426 } 427 428 // NULL terminate it, before using it in strtok(). 429 opwptext[opwmp->datasize] = '\0'; 430 431 linebuff = strtok(opwptext, "\n"); 432 // Step 3: Copy the existing user/password pair 433 // to the new buffer, and update the password if user 434 // already exists. 435 while (linebuff != NULL) { 436 if ((!strncmp(linebuff, forwho, forwholen)) && 437 (linebuff[forwholen] == ':')) { 438 writtensize += 439 snprintf(pwptext + writtensize, 440 pwptextlen - writtensize, 441 "%s:%s\n", forwho, towhat); 442 wroteentry = 1; 443 } else { 444 writtensize += 445 snprintf(pwptext + writtensize, 446 pwptextlen - writtensize, 447 "%s\n", linebuff); 448 } 449 linebuff = strtok(NULL, "\n"); 450 } 451 } 452 // Clear the old password related buffers here, as we are done 453 // with it. 454 free(opwfilebuff); 455 free(opwptext); 456 } else { 457 pwptextlen = 458 forwholen + towhatlen + 3 + EVP_CIPHER_block_size(cipher); 459 pwptext = malloc(pwptextlen); 460 if (pwptext == NULL) { 461 if (opwfile != NULL) { 462 fclose(opwfile); 463 } 464 fclose(pwfile); 465 err = 1; 466 goto done; 467 } 468 } 469 470 if (opwfile != NULL) { 471 fclose(opwfile); 472 } 473 474 if (!wroteentry) { 475 // Write the new user:password pair at the end. 476 writtensize += 477 snprintf(pwptext + writtensize, pwptextlen - writtensize, 478 "%s:%s\n", forwho, towhat); 479 } 480 pwptextlen = writtensize; 481 482 // Step 4: Encrypt the data and write to the temporary file 483 if (RAND_bytes(hash, EVP_MD_block_size(digest)) != 1) { 484 pam_syslog(pamh, LOG_DEBUG, 485 "Hash genertion failed, bailing out"); 486 free(pwptext); 487 fclose(pwfile); 488 err = 1; 489 goto done; 490 } 491 492 // Generate hash key, which will be used for encryption. 493 HMAC(digest, keybuff, keybuffsize, hash, EVP_MD_block_size(digest), key, 494 &keylen); 495 // Generate IV values 496 if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { 497 pam_syslog(pamh, LOG_DEBUG, 498 "IV generation failed, bailing out"); 499 free(pwptext); 500 fclose(pwfile); 501 err = 1; 502 goto done; 503 } 504 505 // Buffer to store encrypted message. 506 pwctext = malloc(pwptextlen + EVP_CIPHER_block_size(cipher)); 507 if (pwctext == NULL) { 508 pam_syslog(pamh, LOG_DEBUG, "Ctext buffer failed, bailing out"); 509 free(pwptext); 510 fclose(pwfile); 511 err = 1; 512 goto done; 513 } 514 515 // Do the encryption 516 if (encrypt_decrypt_data( 517 pamh, 1, cipher, key, keylen, iv, EVP_CIPHER_iv_length(cipher), 518 pwptext, pwptextlen, pwctext, &pwctextlen, mac, &maclen) != 0) { 519 pam_syslog(pamh, LOG_DEBUG, "Encryption failed"); 520 free(pwctext); 521 free(pwptext); 522 fclose(pwfile); 523 err = 1; 524 goto done; 525 } 526 527 // Update the meta password structure. 528 pwmp.hashsize = EVP_MD_block_size(digest); 529 pwmp.ivsize = EVP_CIPHER_iv_length(cipher); 530 pwmp.datasize = writtensize; 531 pwmp.padsize = pwctextlen - writtensize; 532 pwmp.macsize = maclen; 533 534 // Write the meta password structure, followed by hash, iv, encrypted 535 // data & mac. 536 if (fwrite(&pwmp, 1, sizeof(pwmp), pwfile) != sizeof(pwmp)) { 537 pam_syslog(pamh, LOG_DEBUG, "Error in writing meta data"); 538 err = 1; 539 } 540 if (fwrite(hash, 1, pwmp.hashsize, pwfile) != pwmp.hashsize) { 541 pam_syslog(pamh, LOG_DEBUG, "Error in writing hash data"); 542 err = 1; 543 } 544 if (fwrite(iv, 1, pwmp.ivsize, pwfile) != pwmp.ivsize) { 545 pam_syslog(pamh, LOG_DEBUG, "Error in writing IV data"); 546 err = 1; 547 } 548 if (fwrite(pwctext, 1, pwctextlen, pwfile) != pwctextlen) { 549 pam_syslog(pamh, LOG_DEBUG, "Error in encrypted data"); 550 err = 1; 551 } 552 if (fwrite(mac, 1, maclen, pwfile) != maclen) { 553 pam_syslog(pamh, LOG_DEBUG, "Error in writing MAC"); 554 err = 1; 555 } 556 557 free(pwctext); 558 free(pwptext); 559 560 if (fflush(pwfile) || fsync(fileno(pwfile))) { 561 pam_syslog( 562 pamh, LOG_DEBUG, 563 "fflush or fsync error writing entries to special file: %s", 564 tempfilename); 565 err = 1; 566 } 567 568 if (fclose(pwfile)) { 569 pam_syslog(pamh, LOG_DEBUG, 570 "fclose error writing entries to special file: %s", 571 tempfilename); 572 err = 1; 573 } 574 575 done: 576 if (!err) { 577 // Step 5: Rename the temporary file as special password file. 578 if (!rename(tempfilename, filename)) { 579 pam_syslog(pamh, LOG_DEBUG, 580 "password changed for %s in special file", 581 forwho); 582 } else { 583 err = 1; 584 } 585 } 586 587 // Clear out the key buff. 588 memset(keybuff, 0, keybuffsize); 589 590 if (!err) { 591 return PAM_SUCCESS; 592 } else { 593 unlink(tempfilename); 594 return PAM_AUTHTOK_ERR; 595 } 596 } 597 598 /* Password Management API's */ 599 600 /** 601 * @brief pam_sm_chauthtok API 602 * Function which will be called for pam_chauthtok() calls. 603 * 604 * @param[in] pamh - pam handle 605 * @param[in] flags - pam calls related flags 606 * @param[in] argc - argument counts / options 607 * @param[in] argv - array of arguments / options 608 * @return - PAM_SUCCESS for success, others for failure 609 */ 610 int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 611 { 612 int retval = -1; 613 const void *item = NULL; 614 const char *user = NULL; 615 const char *pass_new = NULL, *pass_old = NULL; 616 const char *spec_grp_name = 617 get_option(pamh, "spec_grp_name", argc, argv); 618 const char *spec_pass_file = 619 get_option(pamh, "spec_pass_file", argc, argv); 620 const char *key_file = get_option(pamh, "key_file", argc, argv); 621 622 if (spec_grp_name == NULL || key_file == NULL) { 623 return PAM_IGNORE; 624 } 625 if (flags & PAM_PRELIM_CHECK) { 626 // send success to verify other stacked modules prelim check. 627 return PAM_SUCCESS; 628 } 629 630 retval = pam_get_user(pamh, &user, NULL); 631 if (retval != PAM_SUCCESS) { 632 return retval; 633 } 634 635 // get already read password by the stacked pam module 636 // Note: If there are no previous stacked pam module which read 637 // the new password, then return with AUTHTOK_ERR 638 639 retval = pam_get_item(pamh, PAM_AUTHTOK, &item); 640 if (retval != PAM_SUCCESS || item == NULL) { 641 return PAM_AUTHTOK_ERR; 642 } 643 pass_new = item; 644 645 struct group *grp; 646 int spec_grp_usr = 0; 647 // Verify whether the user belongs to special group. 648 grp = pam_modutil_getgrnam(pamh, spec_grp_name); 649 if (grp != NULL) { 650 while (*(grp->gr_mem) != NULL) { 651 if (strcmp(user, *grp->gr_mem) == 0) { 652 spec_grp_usr = 1; 653 break; 654 } 655 (grp->gr_mem)++; 656 } 657 } 658 659 pam_syslog(pamh, LOG_DEBUG, "User belongs to special grp: %x", 660 spec_grp_usr); 661 662 if (spec_grp_usr) { 663 // verify the new password is acceptable. 664 size_t pass_len = strlen(pass_new); 665 size_t user_len = strlen(user); 666 if (pass_len > MAX_SPEC_GRP_PASS_LENGTH || 667 user_len > MAX_SPEC_GRP_USER_LENGTH) { 668 pam_syslog(pamh, LOG_ERR, 669 "Password length (%zu) / User name length " 670 "(%zu) is not acceptable for IPMI", 671 pass_len, user_len); 672 pass_new = pass_old = NULL; 673 return PAM_AUTHTOK_ERR; 674 } 675 if (spec_pass_file == NULL) { 676 spec_pass_file = DEFAULT_SPEC_PASS_FILE; 677 pam_syslog( 678 pamh, LOG_ERR, 679 "Using default special password file name :%s", 680 spec_pass_file); 681 } 682 if (retval = lock_pwdf()) { 683 pam_syslog(pamh, LOG_ERR, 684 "Failed to lock the passwd file"); 685 return retval; 686 } 687 retval = update_pass_special_file( 688 pamh, key_file, spec_pass_file, user, pass_new); 689 unlock_pwdf(); 690 return retval; 691 } 692 693 return PAM_SUCCESS; 694 } 695 696 /* end of module definition */ 697