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