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