blob: 6617627f01068011a13372002f13c328e61c06b0 [file] [log] [blame]
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +05301/*
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 */
54typedef 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 */
71int 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 */
91void 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 */
105static 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 */
143int 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 */
Patrick Venture9565abd2018-11-14 09:11:59 -0800240FILE *get_temp_file_handle(const pam_handle_t *pamh, char *const tempfilename)
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530241{
242 FILE *tempfile = NULL;
Patrick Ventured0e324a2018-11-14 10:18:50 -0800243 int fd;
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530244 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 */
271int 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
Patrick Venture9565abd2018-11-14 09:11:59 -0800302 // 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
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530306 // 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
Patrick Venture9565abd2018-11-14 09:11:59 -0800331 // 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.
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530334 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 }
Patrick Venture9565abd2018-11-14 09:11:59 -0800354 if ((fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1)
355 || (fchmod(fileno(pwfile), st.st_mode) == -1)) {
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530356 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 }
Patrick Venture9565abd2018-11-14 09:11:59 -0800385 // User & password pairs are mapped as <user
386 // name>:<password>\n. Add +3 for special chars ':',
387 // '\n' and '\0'.
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530388 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)
Patrick Venture9565abd2018-11-14 09:11:59 -0800411 + opwmp->hashsize,
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530412 opwmp->ivsize,
413 opwfilebuff + sizeof(*opwmp)
Patrick Venture9565abd2018-11-14 09:11:59 -0800414 + opwmp->hashsize
415 + opwmp->ivsize,
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530416 opwmp->datasize + opwmp->padsize,
417 opwptext, &opwptextlen,
418 opwfilebuff + sizeof(*opwmp)
Patrick Venture9565abd2018-11-14 09:11:59 -0800419 + opwmp->hashsize
420 + opwmp->ivsize
421 + opwmp->datasize
422 + opwmp->padsize,
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530423 &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(
Patrick Venture9565abd2018-11-14 09:11:59 -0800448 pwptext + writtensize,
449 pwptextlen - writtensize,
450 "%s:%s\n", forwho, towhat);
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530451 wroteentry = 1;
452 } else {
453 writtensize += snprintf(
Patrick Venture9565abd2018-11-14 09:11:59 -0800454 pwptext + writtensize,
455 pwptextlen - writtensize,
456 "%s\n", linebuff);
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530457 }
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) {
Patrick Venture9565abd2018-11-14 09:11:59 -0800484 // user password pair already updated, round it off as per the
485 // CIPHER block
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530486 pwptextlen =
487 block_round(writtensize, EVP_CIPHER_block_size(cipher));
488 // memset the padding bytes
489 memset(pwptext + writtensize, 0, pwptextlen - writtensize);
490 } else {
Patrick Venture9565abd2018-11-14 09:11:59 -0800491 // Write the new user:password pair at the end and round it off
492 // as per the CIPHER block.
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530493 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
596done:
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 */
632int 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()) {
Patrick Venture9565abd2018-11-14 09:11:59 -0800704 pam_syslog(pamh, LOG_ERR,
705 "Failed to lock the passwd file");
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530706 return retval;
707 }
708 retval = update_pass_special_file(
Patrick Venture9565abd2018-11-14 09:11:59 -0800709 pamh, key_file, spec_pass_file, user, pass_new);
Richard Marian Thomaiyar216f2132018-06-12 19:20:48 +0530710 unlock_pwdf();
711 return retval;
712 }
713
714 return PAM_SUCCESS;
715}
716
717/* end of module definition */