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