1216f2139SRichard Marian Thomaiyar /*
2216f2139SRichard Marian Thomaiyar // Copyright (c) 2018 Intel Corporation
3216f2139SRichard Marian Thomaiyar //
4216f2139SRichard Marian Thomaiyar // Licensed under the Apache License, Version 2.0 (the "License");
5216f2139SRichard Marian Thomaiyar // you may not use this file except in compliance with the License.
6216f2139SRichard Marian Thomaiyar // You may obtain a copy of the License at
7216f2139SRichard Marian Thomaiyar //
8216f2139SRichard Marian Thomaiyar // http://www.apache.org/licenses/LICENSE-2.0
9216f2139SRichard Marian Thomaiyar //
10216f2139SRichard Marian Thomaiyar // Unless required by applicable law or agreed to in writing, software
11216f2139SRichard Marian Thomaiyar // distributed under the License is distributed on an "AS IS" BASIS,
12216f2139SRichard Marian Thomaiyar // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13216f2139SRichard Marian Thomaiyar // See the License for the specific language governing permissions and
14216f2139SRichard Marian Thomaiyar // limitations under the License.
15216f2139SRichard Marian Thomaiyar */
16216f2139SRichard Marian Thomaiyar
179e7627a5SPatrick Williams #include <fcntl.h>
189e7627a5SPatrick Williams #include <stdarg.h>
19216f2139SRichard Marian Thomaiyar #include <stdio.h>
20216f2139SRichard Marian Thomaiyar #include <stdlib.h>
21216f2139SRichard Marian Thomaiyar #include <string.h>
22216f2139SRichard Marian Thomaiyar #include <sys/stat.h>
239e7627a5SPatrick Williams #include <syslog.h>
249e7627a5SPatrick Williams #include <unistd.h>
25216f2139SRichard Marian Thomaiyar
26216f2139SRichard Marian Thomaiyar #include <security/pam_ext.h>
279e7627a5SPatrick Williams #include <security/pam_modules.h>
28216f2139SRichard Marian Thomaiyar #include <security/pam_modutil.h>
29216f2139SRichard Marian Thomaiyar
30216f2139SRichard Marian Thomaiyar #include <openssl/evp.h>
31216f2139SRichard Marian Thomaiyar #include <openssl/hmac.h>
32216f2139SRichard Marian Thomaiyar #include <openssl/rand.h>
33216f2139SRichard Marian Thomaiyar
34216f2139SRichard Marian Thomaiyar /*
35216f2139SRichard Marian Thomaiyar * This module is intended to save password of special group user
36216f2139SRichard Marian Thomaiyar *
37216f2139SRichard Marian Thomaiyar */
38216f2139SRichard Marian Thomaiyar
39216f2139SRichard Marian Thomaiyar #define MAX_SPEC_GRP_PASS_LENGTH 20
40216f2139SRichard Marian Thomaiyar #define MAX_SPEC_GRP_USER_LENGTH 16
41216f2139SRichard Marian Thomaiyar #define MAX_KEY_SIZE 8
42216f2139SRichard Marian Thomaiyar #define DEFAULT_SPEC_PASS_FILE "/etc/ipmi_pass"
43216f2139SRichard Marian Thomaiyar #define META_PASSWD_SIG "=OPENBMC="
44216f2139SRichard Marian Thomaiyar
45216f2139SRichard Marian Thomaiyar /*
46216f2139SRichard Marian Thomaiyar * Meta data struct for storing the encrypted password file
47216f2139SRichard Marian Thomaiyar * Note: Followed by this structure, the real data of hash, iv, encrypted data
48216f2139SRichard Marian Thomaiyar * with pad and mac are stored.
49216f2139SRichard Marian Thomaiyar * Decrypted data will hold user name & password for every new line with format
50216f2139SRichard Marian Thomaiyar * like <user name>:<password>\n
51216f2139SRichard Marian Thomaiyar */
52216f2139SRichard Marian Thomaiyar typedef struct metapassstruct {
53216f2139SRichard Marian Thomaiyar char signature[10];
54*d9c11abdSManojkiran Eda unsigned char reserved[2];
55216f2139SRichard Marian Thomaiyar size_t hashsize;
56216f2139SRichard Marian Thomaiyar size_t ivsize;
57216f2139SRichard Marian Thomaiyar size_t datasize;
58216f2139SRichard Marian Thomaiyar size_t padsize;
59216f2139SRichard Marian Thomaiyar size_t macsize;
60216f2139SRichard Marian Thomaiyar } metapassstruct;
61216f2139SRichard Marian Thomaiyar
62216f2139SRichard Marian Thomaiyar /**
63216f2139SRichard Marian Thomaiyar * @brief to acquire lock for atomic operation
64216f2139SRichard Marian Thomaiyar * Internally uses lckpwdf to acquire the lock. Tries to acquire the lock
65216f2139SRichard Marian Thomaiyar * using lckpwdf() in interval of 1ms, with maximum of 100 attempts.
66216f2139SRichard Marian Thomaiyar *
67216f2139SRichard Marian Thomaiyar * @return PAM_SUCCESS for success / PAM_AUTHTOK_LOCK_BUSY for failure
68216f2139SRichard Marian Thomaiyar */
lock_pwdf(void)69216f2139SRichard Marian Thomaiyar int lock_pwdf(void)
70216f2139SRichard Marian Thomaiyar {
71216f2139SRichard Marian Thomaiyar int i;
72216f2139SRichard Marian Thomaiyar int retval;
73216f2139SRichard Marian Thomaiyar
74216f2139SRichard Marian Thomaiyar i = 0;
75216f2139SRichard Marian Thomaiyar while ((retval = lckpwdf()) != 0 && i < 100) {
76216f2139SRichard Marian Thomaiyar usleep(1000);
77216f2139SRichard Marian Thomaiyar i++;
78216f2139SRichard Marian Thomaiyar }
79216f2139SRichard Marian Thomaiyar if (retval != 0) {
80216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_LOCK_BUSY;
81216f2139SRichard Marian Thomaiyar }
82216f2139SRichard Marian Thomaiyar return PAM_SUCCESS;
83216f2139SRichard Marian Thomaiyar }
84216f2139SRichard Marian Thomaiyar
85216f2139SRichard Marian Thomaiyar /**
86216f2139SRichard Marian Thomaiyar * @brief unlock the acquired lock
87216f2139SRichard Marian Thomaiyar * Internally uses ulckpwdf to release the lock
88216f2139SRichard Marian Thomaiyar */
unlock_pwdf(void)89216f2139SRichard Marian Thomaiyar void unlock_pwdf(void)
90216f2139SRichard Marian Thomaiyar {
91216f2139SRichard Marian Thomaiyar ulckpwdf();
92216f2139SRichard Marian Thomaiyar }
93216f2139SRichard Marian Thomaiyar
94216f2139SRichard Marian Thomaiyar /**
95216f2139SRichard Marian Thomaiyar * @brief to get argument value of option
96216f2139SRichard Marian Thomaiyar * Function to get the value of argument options.
97216f2139SRichard Marian Thomaiyar *
98216f2139SRichard Marian Thomaiyar * @param[in] pamh - pam handle
99216f2139SRichard Marian Thomaiyar * @param[in] option - argument option to which value has to returned
100216f2139SRichard Marian Thomaiyar * @param[in] argc - argument count
101216f2139SRichard Marian Thomaiyar * @param[in] argv - array of arguments
102216f2139SRichard Marian Thomaiyar */
get_option(const pam_handle_t * pamh,const char * option,int argc,const char ** argv)103216f2139SRichard Marian Thomaiyar static const char *get_option(const pam_handle_t *pamh, const char *option,
104216f2139SRichard Marian Thomaiyar int argc, const char **argv)
105216f2139SRichard Marian Thomaiyar {
106bb71716bSVernon Mauery if (!pamh) {
107bb71716bSVernon Mauery return NULL;
108bb71716bSVernon Mauery }
109bb71716bSVernon Mauery
110216f2139SRichard Marian Thomaiyar int i;
111216f2139SRichard Marian Thomaiyar size_t len;
112216f2139SRichard Marian Thomaiyar
113216f2139SRichard Marian Thomaiyar len = strlen(option);
114216f2139SRichard Marian Thomaiyar
115216f2139SRichard Marian Thomaiyar for (i = 0; i < argc; ++i) {
116216f2139SRichard Marian Thomaiyar if (strncmp(option, argv[i], len) == 0) {
117216f2139SRichard Marian Thomaiyar if (argv[i][len] == '=') {
118216f2139SRichard Marian Thomaiyar return &argv[i][len + 1];
119216f2139SRichard Marian Thomaiyar }
120216f2139SRichard Marian Thomaiyar }
121216f2139SRichard Marian Thomaiyar }
122216f2139SRichard Marian Thomaiyar return NULL;
123216f2139SRichard Marian Thomaiyar }
124216f2139SRichard Marian Thomaiyar
125216f2139SRichard Marian Thomaiyar /**
126216f2139SRichard Marian Thomaiyar * @brief encrypt or decrypt function
127216f2139SRichard Marian Thomaiyar * Function which will do the encryption or decryption of the data.
128216f2139SRichard Marian Thomaiyar *
129216f2139SRichard Marian Thomaiyar * @param[in] pamh - pam handle.
130216f2139SRichard Marian Thomaiyar * @param[in] isencrypt - encrypt or decrypt option.
131216f2139SRichard Marian Thomaiyar * @param[in] cipher - EVP_CIPHER to be used
132216f2139SRichard Marian Thomaiyar * @param[in] key - key which has to be used in EVP_CIPHER api's.
133216f2139SRichard Marian Thomaiyar * @param[in] keylen - Length of the key.
134216f2139SRichard Marian Thomaiyar * @param[in] iv - Initialization vector data, used along with key
135216f2139SRichard Marian Thomaiyar * @param[in] ivlen - Length of IV.
136216f2139SRichard Marian Thomaiyar * @param[in] inbytes - buffer which has to be encrypted or decrypted.
137216f2139SRichard Marian Thomaiyar * @param[in] inbyteslen - length of input buffer.
138216f2139SRichard Marian Thomaiyar * @param[in] outbytes - buffer to store decrypted or encrypted data.
139216f2139SRichard Marian Thomaiyar * @param[in] outbyteslen - length of output buffer
140216f2139SRichard Marian Thomaiyar * @param[in/out] mac - checksum to cross verify. Will be verified for decrypt
141216f2139SRichard Marian Thomaiyar * and returns for encrypt.
142216f2139SRichard Marian Thomaiyar * @param[in/out] maclen - length of checksum
143216f2139SRichard Marian Thomaiyar * @return - 0 for success -1 for failures.
144216f2139SRichard Marian Thomaiyar */
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)145216f2139SRichard Marian Thomaiyar int encrypt_decrypt_data(const pam_handle_t *pamh, int isencrypt,
146bb71716bSVernon Mauery const EVP_CIPHER *cipher, const unsigned char *key,
147bb71716bSVernon Mauery int keylen, const unsigned char *iv, int ivlen,
148bb71716bSVernon Mauery const unsigned char *inbytes, size_t inbyteslen,
149bb71716bSVernon Mauery unsigned char *outbytes, size_t *outbyteslen,
150bb71716bSVernon Mauery unsigned char *mac, unsigned int *maclen)
151216f2139SRichard Marian Thomaiyar {
152216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX *ctx;
153216f2139SRichard Marian Thomaiyar const EVP_MD *digest;
154bb71716bSVernon Mauery int outEVPlen = 0;
155216f2139SRichard Marian Thomaiyar int retval = 0;
156216f2139SRichard Marian Thomaiyar size_t outlen = 0;
157216f2139SRichard Marian Thomaiyar
1589e7627a5SPatrick Williams if (cipher == NULL || key == NULL || iv == NULL || inbytes == NULL ||
1599e7627a5SPatrick Williams outbytes == NULL || mac == NULL || inbyteslen == 0 ||
1609e7627a5SPatrick Williams EVP_CIPHER_key_length(cipher) > keylen ||
1619e7627a5SPatrick Williams EVP_CIPHER_iv_length(cipher) > ivlen) {
162216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Invalid inputs");
163216f2139SRichard Marian Thomaiyar return -1;
164216f2139SRichard Marian Thomaiyar }
165216f2139SRichard Marian Thomaiyar
166216f2139SRichard Marian Thomaiyar digest = EVP_sha256();
167216f2139SRichard Marian Thomaiyar if (!isencrypt) {
168bb71716bSVernon Mauery unsigned char calmac[EVP_MAX_MD_SIZE];
169bb71716bSVernon Mauery unsigned int calmaclen = 0;
170216f2139SRichard Marian Thomaiyar // calculate MAC for the encrypted message.
1719e7627a5SPatrick Williams if (NULL == HMAC(digest, key, keylen, inbytes, inbyteslen,
1729e7627a5SPatrick Williams calmac, &calmaclen)) {
173216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
174216f2139SRichard Marian Thomaiyar "Failed to verify authentication %d",
175216f2139SRichard Marian Thomaiyar retval);
176216f2139SRichard Marian Thomaiyar return -1;
177216f2139SRichard Marian Thomaiyar }
1789e7627a5SPatrick Williams if (!((calmaclen == *maclen) &&
1799e7627a5SPatrick Williams (memcmp(calmac, mac, calmaclen) == 0))) {
180216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
181216f2139SRichard Marian Thomaiyar "Authenticated message doesn't match %d, %d",
182216f2139SRichard Marian Thomaiyar calmaclen, *maclen);
183216f2139SRichard Marian Thomaiyar return -1;
184216f2139SRichard Marian Thomaiyar }
185216f2139SRichard Marian Thomaiyar }
186216f2139SRichard Marian Thomaiyar
187216f2139SRichard Marian Thomaiyar ctx = EVP_CIPHER_CTX_new();
188216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX_set_padding(ctx, 1);
189216f2139SRichard Marian Thomaiyar
190216f2139SRichard Marian Thomaiyar // Set key & IV
191216f2139SRichard Marian Thomaiyar retval = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, isencrypt);
192216f2139SRichard Marian Thomaiyar if (!retval) {
193216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "EVP_CipherInit_ex failed with %d",
194216f2139SRichard Marian Thomaiyar retval);
195216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX_free(ctx);
196216f2139SRichard Marian Thomaiyar return -1;
197216f2139SRichard Marian Thomaiyar }
198216f2139SRichard Marian Thomaiyar if ((retval = EVP_CipherUpdate(ctx, outbytes + outlen, &outEVPlen,
199216f2139SRichard Marian Thomaiyar inbytes, inbyteslen))) {
200216f2139SRichard Marian Thomaiyar outlen += outEVPlen;
201e4b13e67SPatrick Williams if ((retval = EVP_CipherFinal(ctx, outbytes + outlen,
202e4b13e67SPatrick Williams &outEVPlen))) {
203216f2139SRichard Marian Thomaiyar outlen += outEVPlen;
204216f2139SRichard Marian Thomaiyar *outbyteslen = outlen;
205216f2139SRichard Marian Thomaiyar } else {
206216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
207216f2139SRichard Marian Thomaiyar "EVP_CipherFinal returns with %d", retval);
208216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX_free(ctx);
209216f2139SRichard Marian Thomaiyar return -1;
210216f2139SRichard Marian Thomaiyar }
211216f2139SRichard Marian Thomaiyar } else {
212216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "EVP_CipherUpdate returns with %d",
213216f2139SRichard Marian Thomaiyar retval);
214216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX_free(ctx);
215216f2139SRichard Marian Thomaiyar return -1;
216216f2139SRichard Marian Thomaiyar }
217216f2139SRichard Marian Thomaiyar EVP_CIPHER_CTX_free(ctx);
218216f2139SRichard Marian Thomaiyar
219216f2139SRichard Marian Thomaiyar if (isencrypt) {
220216f2139SRichard Marian Thomaiyar // Create MAC for the encrypted message.
2219e7627a5SPatrick Williams if (NULL == HMAC(digest, key, keylen, outbytes, *outbyteslen,
2229e7627a5SPatrick Williams mac, maclen)) {
223216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
224216f2139SRichard Marian Thomaiyar "Failed to create authentication %d",
225216f2139SRichard Marian Thomaiyar retval);
226216f2139SRichard Marian Thomaiyar return -1;
227216f2139SRichard Marian Thomaiyar }
228216f2139SRichard Marian Thomaiyar }
229216f2139SRichard Marian Thomaiyar return 0;
230216f2139SRichard Marian Thomaiyar }
231216f2139SRichard Marian Thomaiyar
232216f2139SRichard Marian Thomaiyar /**
233216f2139SRichard Marian Thomaiyar * @brief get temporary file handle
234216f2139SRichard Marian Thomaiyar * Function to get the temporary file handle, created using mkstemp
235216f2139SRichard Marian Thomaiyar *
236216f2139SRichard Marian Thomaiyar * @param[in] pamh - pam handle.
237216f2139SRichard Marian Thomaiyar * @param[in/out] tempfilename - tempfilename, which will be used in mkstemp.
238216f2139SRichard Marian Thomaiyar * @return - FILE handle for success. NULL for failure
239216f2139SRichard Marian Thomaiyar */
get_temp_file_handle(const pam_handle_t * pamh,char * const tempfilename)240216f2139SRichard Marian Thomaiyar FILE *get_temp_file_handle(const pam_handle_t *pamh, char *const tempfilename)
241216f2139SRichard Marian Thomaiyar {
242216f2139SRichard Marian Thomaiyar FILE *tempfile = NULL;
243d0e324abSPatrick Venture int fd;
244216f2139SRichard Marian Thomaiyar int oldmask = umask(077);
245216f2139SRichard Marian Thomaiyar fd = mkstemp(tempfilename);
246216f2139SRichard Marian Thomaiyar if (fd == -1) {
247216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in creating temp file");
248216f2139SRichard Marian Thomaiyar umask(oldmask);
249216f2139SRichard Marian Thomaiyar return NULL;
250216f2139SRichard Marian Thomaiyar }
251216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Temporary file name is %s", tempfilename);
252216f2139SRichard Marian Thomaiyar
253216f2139SRichard Marian Thomaiyar tempfile = fdopen(fd, "w");
254216f2139SRichard Marian Thomaiyar umask(oldmask);
255216f2139SRichard Marian Thomaiyar return tempfile;
256216f2139SRichard Marian Thomaiyar }
257216f2139SRichard Marian Thomaiyar
258216f2139SRichard Marian Thomaiyar /**
259216f2139SRichard Marian Thomaiyar * @brief updates special password file
260216f2139SRichard Marian Thomaiyar * Function to update the special password file. Stores the password against
261216f2139SRichard Marian Thomaiyar * username in encrypted form along with meta data
262216f2139SRichard Marian Thomaiyar *
263216f2139SRichard Marian Thomaiyar * @param[in] pamh - pam handle.
264216f2139SRichard Marian Thomaiyar * @param[in] keyfilename - file name where key seed is stored.
265216f2139SRichard Marian Thomaiyar * @param[in] filename - special password file name
266216f2139SRichard Marian Thomaiyar * @param[in] forwho - name of the user
267216f2139SRichard Marian Thomaiyar * @param[in] towhat - password that has to stored in encrypted form
268216f2139SRichard Marian Thomaiyar * @return - PAM_SUCCESS for success or PAM_AUTHTOK_ERR for failure
269216f2139SRichard Marian Thomaiyar */
update_pass_special_file(const pam_handle_t * pamh,const char * keyfilename,const char * filename,const char * forwho,const char * towhat)270216f2139SRichard Marian Thomaiyar int update_pass_special_file(const pam_handle_t *pamh, const char *keyfilename,
271216f2139SRichard Marian Thomaiyar const char *filename, const char *forwho,
272216f2139SRichard Marian Thomaiyar const char *towhat)
273216f2139SRichard Marian Thomaiyar {
274216f2139SRichard Marian Thomaiyar struct stat st;
275216f2139SRichard Marian Thomaiyar FILE *pwfile = NULL, *opwfile = NULL, *keyfile = NULL;
276216f2139SRichard Marian Thomaiyar int err = 0, wroteentry = 0;
277216f2139SRichard Marian Thomaiyar char tempfilename[1024];
278216f2139SRichard Marian Thomaiyar size_t forwholen = strlen(forwho);
279216f2139SRichard Marian Thomaiyar size_t towhatlen = strlen(towhat);
280216f2139SRichard Marian Thomaiyar char keybuff[MAX_KEY_SIZE] = { 0 };
281216f2139SRichard Marian Thomaiyar size_t keybuffsize = sizeof(keybuff);
282216f2139SRichard Marian Thomaiyar
283216f2139SRichard Marian Thomaiyar const EVP_CIPHER *cipher = EVP_aes_128_cbc();
284216f2139SRichard Marian Thomaiyar const EVP_MD *digest = EVP_sha256();
285216f2139SRichard Marian Thomaiyar
286bb71716bSVernon Mauery char *linebuff = NULL;
287bb71716bSVernon Mauery unsigned char *opwfilebuff = NULL;
288bb71716bSVernon Mauery unsigned char *opwptext = NULL;
289216f2139SRichard Marian Thomaiyar size_t opwptextlen = 0, opwfilesize = 0;
290216f2139SRichard Marian Thomaiyar metapassstruct *opwmp = NULL;
291216f2139SRichard Marian Thomaiyar
292bb71716bSVernon Mauery unsigned char *pwptext = NULL;
293bb71716bSVernon Mauery unsigned char *pwctext = NULL;
294bb71716bSVernon Mauery size_t pwctextlen = 0, pwptextlen = 0;
295bb71716bSVernon Mauery unsigned int maclen = 0;
296bb71716bSVernon Mauery size_t writtensize = 0;
297bb71716bSVernon Mauery unsigned int keylen = 0;
298216f2139SRichard Marian Thomaiyar metapassstruct pwmp = { META_PASSWD_SIG, { 0, 0 }, .0, 0, 0, 0, 0 };
299bb71716bSVernon Mauery unsigned char mac[EVP_MAX_MD_SIZE] = { 0 };
300216f2139SRichard Marian Thomaiyar unsigned char key[EVP_MAX_KEY_LENGTH];
301bb71716bSVernon Mauery unsigned char iv[EVP_CIPHER_iv_length(cipher)];
302bb71716bSVernon Mauery unsigned char hash[EVP_MD_block_size(digest)];
303216f2139SRichard Marian Thomaiyar
304216f2139SRichard Marian Thomaiyar // Following steps are performed in this function.
305216f2139SRichard Marian Thomaiyar // Step 1: Create a temporary file - always update temporary file, and
306*d9c11abdSManojkiran Eda // then swap it with original one, only if everything succeeded at the
3079565abd6SPatrick Venture // end. Step 2: If file already exists, read the old file and decrypt it
3089565abd6SPatrick Venture // in buffer Step 3: Copy user/password pair from old buffer to new
3099565abd6SPatrick Venture // buffer, and update, if the user already exists with the new password
310216f2139SRichard Marian Thomaiyar // Step 4: Encrypt the new buffer and write it to the temp file created
311216f2139SRichard Marian Thomaiyar // at Step 1.
312216f2139SRichard Marian Thomaiyar // Step 5. rename the temporary file name as special password file.
313216f2139SRichard Marian Thomaiyar
314216f2139SRichard Marian Thomaiyar // verify the tempfilename buffer is enough to hold
315216f2139SRichard Marian Thomaiyar // filename_XXXXXX (+1 for null).
3169e7627a5SPatrick Williams if (strlen(filename) >
3179e7627a5SPatrick Williams (sizeof(tempfilename) - strlen("__XXXXXX") - 1)) {
318216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Not enough buffer, bailing out");
319216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_ERR;
320216f2139SRichard Marian Thomaiyar }
321216f2139SRichard Marian Thomaiyar // Fetch the key from key file name.
322216f2139SRichard Marian Thomaiyar keyfile = fopen(keyfilename, "r");
323216f2139SRichard Marian Thomaiyar if (keyfile == NULL) {
324216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Unable to open key file %s",
325216f2139SRichard Marian Thomaiyar keyfilename);
326216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_ERR;
327216f2139SRichard Marian Thomaiyar }
328216f2139SRichard Marian Thomaiyar if (fread(keybuff, 1, keybuffsize, keyfile) != keybuffsize) {
329216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Key file read failed");
330216f2139SRichard Marian Thomaiyar fclose(keyfile);
331216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_ERR;
332216f2139SRichard Marian Thomaiyar }
333216f2139SRichard Marian Thomaiyar fclose(keyfile);
334216f2139SRichard Marian Thomaiyar
3359565abd6SPatrick Venture // Step 1: Try to create a temporary file, in which all the update will
3369565abd6SPatrick Venture // happen then it will be renamed to the original file. This is done to
3379565abd6SPatrick Venture // have atomic operation.
338216f2139SRichard Marian Thomaiyar snprintf(tempfilename, sizeof(tempfilename), "%s__XXXXXX", filename);
339216f2139SRichard Marian Thomaiyar pwfile = get_temp_file_handle(pamh, tempfilename);
340216f2139SRichard Marian Thomaiyar if (pwfile == NULL) {
341216f2139SRichard Marian Thomaiyar err = 1;
342216f2139SRichard Marian Thomaiyar goto done;
343216f2139SRichard Marian Thomaiyar }
344216f2139SRichard Marian Thomaiyar
345216f2139SRichard Marian Thomaiyar // Update temporary file stat by reading the special password file
346216f2139SRichard Marian Thomaiyar opwfile = fopen(filename, "r");
347216f2139SRichard Marian Thomaiyar if (opwfile != NULL) {
348216f2139SRichard Marian Thomaiyar if (fstat(fileno(opwfile), &st) == -1) {
349216f2139SRichard Marian Thomaiyar fclose(opwfile);
350216f2139SRichard Marian Thomaiyar fclose(pwfile);
351216f2139SRichard Marian Thomaiyar err = 1;
352216f2139SRichard Marian Thomaiyar goto done;
353216f2139SRichard Marian Thomaiyar }
354216f2139SRichard Marian Thomaiyar } else { // Create with this settings if file is not present.
355216f2139SRichard Marian Thomaiyar memset(&st, 0, sizeof(st));
356216f2139SRichard Marian Thomaiyar }
357f3919c43SVernon Mauery // Override the file permission with S_IWUSR | S_IRUSR
358f3919c43SVernon Mauery st.st_mode = S_IWUSR | S_IRUSR;
3599e7627a5SPatrick Williams if ((fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) ||
3609e7627a5SPatrick Williams (fchmod(fileno(pwfile), st.st_mode) == -1)) {
361216f2139SRichard Marian Thomaiyar if (opwfile != NULL) {
362216f2139SRichard Marian Thomaiyar fclose(opwfile);
363216f2139SRichard Marian Thomaiyar }
364216f2139SRichard Marian Thomaiyar fclose(pwfile);
365216f2139SRichard Marian Thomaiyar err = 1;
366216f2139SRichard Marian Thomaiyar goto done;
367216f2139SRichard Marian Thomaiyar }
368216f2139SRichard Marian Thomaiyar opwfilesize = st.st_size;
369216f2139SRichard Marian Thomaiyar
370216f2139SRichard Marian Thomaiyar // Step 2: Read existing special password file and decrypt the data.
371216f2139SRichard Marian Thomaiyar if (opwfilesize) {
372216f2139SRichard Marian Thomaiyar opwfilebuff = malloc(opwfilesize);
373216f2139SRichard Marian Thomaiyar if (opwfilebuff == NULL) {
374216f2139SRichard Marian Thomaiyar fclose(opwfile);
375216f2139SRichard Marian Thomaiyar fclose(pwfile);
376216f2139SRichard Marian Thomaiyar err = 1;
377216f2139SRichard Marian Thomaiyar goto done;
378216f2139SRichard Marian Thomaiyar }
379216f2139SRichard Marian Thomaiyar
380216f2139SRichard Marian Thomaiyar if (fread(opwfilebuff, 1, opwfilesize, opwfile)) {
381216f2139SRichard Marian Thomaiyar opwmp = (metapassstruct *)opwfilebuff;
382216f2139SRichard Marian Thomaiyar opwptext = malloc(opwmp->datasize + opwmp->padsize);
383216f2139SRichard Marian Thomaiyar if (opwptext == NULL) {
384216f2139SRichard Marian Thomaiyar free(opwfilebuff);
385216f2139SRichard Marian Thomaiyar fclose(opwfile);
386216f2139SRichard Marian Thomaiyar fclose(pwfile);
387216f2139SRichard Marian Thomaiyar err = 1;
388216f2139SRichard Marian Thomaiyar goto done;
389216f2139SRichard Marian Thomaiyar }
3909565abd6SPatrick Venture // User & password pairs are mapped as <user
3919565abd6SPatrick Venture // name>:<password>\n. Add +3 for special chars ':',
3929565abd6SPatrick Venture // '\n' and '\0'.
3939e7627a5SPatrick Williams pwptextlen = opwmp->datasize + forwholen + towhatlen +
3949e7627a5SPatrick Williams 3 + EVP_CIPHER_block_size(cipher);
395216f2139SRichard Marian Thomaiyar pwptext = malloc(pwptextlen);
396216f2139SRichard Marian Thomaiyar if (pwptext == NULL) {
397216f2139SRichard Marian Thomaiyar free(opwptext);
398216f2139SRichard Marian Thomaiyar free(opwfilebuff);
399216f2139SRichard Marian Thomaiyar fclose(opwfile);
400216f2139SRichard Marian Thomaiyar fclose(pwfile);
401216f2139SRichard Marian Thomaiyar err = 1;
402216f2139SRichard Marian Thomaiyar goto done;
403216f2139SRichard Marian Thomaiyar }
404216f2139SRichard Marian Thomaiyar
405216f2139SRichard Marian Thomaiyar // First get the hashed key to decrypt
406216f2139SRichard Marian Thomaiyar HMAC(digest, keybuff, keybuffsize,
407216f2139SRichard Marian Thomaiyar opwfilebuff + sizeof(*opwmp), opwmp->hashsize, key,
408216f2139SRichard Marian Thomaiyar &keylen);
409216f2139SRichard Marian Thomaiyar
410bb71716bSVernon Mauery unsigned int tmpmacsize = opwmp->macsize;
411216f2139SRichard Marian Thomaiyar // Skip decryption if there is no data
412216f2139SRichard Marian Thomaiyar if (opwmp->datasize != 0) {
413216f2139SRichard Marian Thomaiyar // Do the decryption
414216f2139SRichard Marian Thomaiyar if (encrypt_decrypt_data(
415216f2139SRichard Marian Thomaiyar pamh, 0, cipher, key, keylen,
4169e7627a5SPatrick Williams opwfilebuff + sizeof(*opwmp) +
4179e7627a5SPatrick Williams opwmp->hashsize,
418216f2139SRichard Marian Thomaiyar opwmp->ivsize,
4199e7627a5SPatrick Williams opwfilebuff + sizeof(*opwmp) +
420e4b13e67SPatrick Williams opwmp->hashsize +
421e4b13e67SPatrick Williams opwmp->ivsize,
422216f2139SRichard Marian Thomaiyar opwmp->datasize + opwmp->padsize,
423216f2139SRichard Marian Thomaiyar opwptext, &opwptextlen,
4249e7627a5SPatrick Williams opwfilebuff + sizeof(*opwmp) +
425e4b13e67SPatrick Williams opwmp->hashsize +
426e4b13e67SPatrick Williams opwmp->ivsize +
427e4b13e67SPatrick Williams opwmp->datasize +
428e4b13e67SPatrick Williams opwmp->padsize,
429bb71716bSVernon Mauery &tmpmacsize) != 0) {
430216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
431216f2139SRichard Marian Thomaiyar "Decryption failed");
432216f2139SRichard Marian Thomaiyar free(pwptext);
433216f2139SRichard Marian Thomaiyar free(opwptext);
434216f2139SRichard Marian Thomaiyar free(opwfilebuff);
435216f2139SRichard Marian Thomaiyar fclose(opwfile);
436216f2139SRichard Marian Thomaiyar fclose(pwfile);
437216f2139SRichard Marian Thomaiyar err = 1;
438216f2139SRichard Marian Thomaiyar goto done;
439216f2139SRichard Marian Thomaiyar }
440bb71716bSVernon Mauery opwmp->macsize = tmpmacsize;
441216f2139SRichard Marian Thomaiyar }
442216f2139SRichard Marian Thomaiyar
443216f2139SRichard Marian Thomaiyar // NULL terminate it, before using it in strtok().
444216f2139SRichard Marian Thomaiyar opwptext[opwmp->datasize] = '\0';
445216f2139SRichard Marian Thomaiyar
446bb71716bSVernon Mauery linebuff = strtok((char *)opwptext, "\n");
447216f2139SRichard Marian Thomaiyar // Step 3: Copy the existing user/password pair
448216f2139SRichard Marian Thomaiyar // to the new buffer, and update the password if user
449216f2139SRichard Marian Thomaiyar // already exists.
450216f2139SRichard Marian Thomaiyar while (linebuff != NULL) {
4519e7627a5SPatrick Williams if ((!strncmp(linebuff, forwho, forwholen)) &&
4529e7627a5SPatrick Williams (linebuff[forwholen] == ':')) {
453bb71716bSVernon Mauery writtensize += snprintf(
454bb71716bSVernon Mauery (char *)pwptext + writtensize,
455e4b13e67SPatrick Williams pwptextlen - writtensize,
456e4b13e67SPatrick Williams "%s:%s\n", forwho, towhat);
457216f2139SRichard Marian Thomaiyar wroteentry = 1;
458216f2139SRichard Marian Thomaiyar } else {
459bb71716bSVernon Mauery writtensize += snprintf(
460bb71716bSVernon Mauery (char *)pwptext + writtensize,
461e4b13e67SPatrick Williams pwptextlen - writtensize,
462e4b13e67SPatrick Williams "%s\n", linebuff);
463216f2139SRichard Marian Thomaiyar }
464216f2139SRichard Marian Thomaiyar linebuff = strtok(NULL, "\n");
465216f2139SRichard Marian Thomaiyar }
466216f2139SRichard Marian Thomaiyar }
467216f2139SRichard Marian Thomaiyar // Clear the old password related buffers here, as we are done
468216f2139SRichard Marian Thomaiyar // with it.
469216f2139SRichard Marian Thomaiyar free(opwfilebuff);
470216f2139SRichard Marian Thomaiyar free(opwptext);
471216f2139SRichard Marian Thomaiyar } else {
472e4b13e67SPatrick Williams pwptextlen = forwholen + towhatlen + 3 +
473e4b13e67SPatrick Williams EVP_CIPHER_block_size(cipher);
474216f2139SRichard Marian Thomaiyar pwptext = malloc(pwptextlen);
475216f2139SRichard Marian Thomaiyar if (pwptext == NULL) {
476216f2139SRichard Marian Thomaiyar if (opwfile != NULL) {
477216f2139SRichard Marian Thomaiyar fclose(opwfile);
478216f2139SRichard Marian Thomaiyar }
479216f2139SRichard Marian Thomaiyar fclose(pwfile);
480216f2139SRichard Marian Thomaiyar err = 1;
481216f2139SRichard Marian Thomaiyar goto done;
482216f2139SRichard Marian Thomaiyar }
483216f2139SRichard Marian Thomaiyar }
484216f2139SRichard Marian Thomaiyar
485216f2139SRichard Marian Thomaiyar if (opwfile != NULL) {
486216f2139SRichard Marian Thomaiyar fclose(opwfile);
487216f2139SRichard Marian Thomaiyar }
488216f2139SRichard Marian Thomaiyar
48965edb939SRichard Marian Thomaiyar if (!wroteentry) {
49065edb939SRichard Marian Thomaiyar // Write the new user:password pair at the end.
491bb71716bSVernon Mauery writtensize += snprintf((char *)pwptext + writtensize,
492bb71716bSVernon Mauery pwptextlen - writtensize, "%s:%s\n",
493bb71716bSVernon Mauery forwho, towhat);
494216f2139SRichard Marian Thomaiyar }
49565edb939SRichard Marian Thomaiyar pwptextlen = writtensize;
496216f2139SRichard Marian Thomaiyar
497216f2139SRichard Marian Thomaiyar // Step 4: Encrypt the data and write to the temporary file
498216f2139SRichard Marian Thomaiyar if (RAND_bytes(hash, EVP_MD_block_size(digest)) != 1) {
499216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
500*d9c11abdSManojkiran Eda "Hash generation failed, bailing out");
501216f2139SRichard Marian Thomaiyar free(pwptext);
502216f2139SRichard Marian Thomaiyar fclose(pwfile);
503216f2139SRichard Marian Thomaiyar err = 1;
504216f2139SRichard Marian Thomaiyar goto done;
505216f2139SRichard Marian Thomaiyar }
506216f2139SRichard Marian Thomaiyar
507216f2139SRichard Marian Thomaiyar // Generate hash key, which will be used for encryption.
508216f2139SRichard Marian Thomaiyar HMAC(digest, keybuff, keybuffsize, hash, EVP_MD_block_size(digest), key,
509216f2139SRichard Marian Thomaiyar &keylen);
510216f2139SRichard Marian Thomaiyar // Generate IV values
511216f2139SRichard Marian Thomaiyar if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
512216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
513216f2139SRichard Marian Thomaiyar "IV generation failed, bailing out");
514216f2139SRichard Marian Thomaiyar free(pwptext);
515216f2139SRichard Marian Thomaiyar fclose(pwfile);
516216f2139SRichard Marian Thomaiyar err = 1;
517216f2139SRichard Marian Thomaiyar goto done;
518216f2139SRichard Marian Thomaiyar }
519216f2139SRichard Marian Thomaiyar
520216f2139SRichard Marian Thomaiyar // Buffer to store encrypted message.
521216f2139SRichard Marian Thomaiyar pwctext = malloc(pwptextlen + EVP_CIPHER_block_size(cipher));
522216f2139SRichard Marian Thomaiyar if (pwctext == NULL) {
523216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Ctext buffer failed, bailing out");
524216f2139SRichard Marian Thomaiyar free(pwptext);
525216f2139SRichard Marian Thomaiyar fclose(pwfile);
526216f2139SRichard Marian Thomaiyar err = 1;
527216f2139SRichard Marian Thomaiyar goto done;
528216f2139SRichard Marian Thomaiyar }
529216f2139SRichard Marian Thomaiyar
530216f2139SRichard Marian Thomaiyar // Do the encryption
531e4b13e67SPatrick Williams if (encrypt_decrypt_data(pamh, 1, cipher, key, keylen, iv,
532e4b13e67SPatrick Williams EVP_CIPHER_iv_length(cipher), pwptext,
533e4b13e67SPatrick Williams pwptextlen, pwctext, &pwctextlen, mac,
534e4b13e67SPatrick Williams &maclen) != 0) {
535216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Encryption failed");
536216f2139SRichard Marian Thomaiyar free(pwctext);
537216f2139SRichard Marian Thomaiyar free(pwptext);
538216f2139SRichard Marian Thomaiyar fclose(pwfile);
539216f2139SRichard Marian Thomaiyar err = 1;
540216f2139SRichard Marian Thomaiyar goto done;
541216f2139SRichard Marian Thomaiyar }
542216f2139SRichard Marian Thomaiyar
543216f2139SRichard Marian Thomaiyar // Update the meta password structure.
544216f2139SRichard Marian Thomaiyar pwmp.hashsize = EVP_MD_block_size(digest);
545216f2139SRichard Marian Thomaiyar pwmp.ivsize = EVP_CIPHER_iv_length(cipher);
546216f2139SRichard Marian Thomaiyar pwmp.datasize = writtensize;
547216f2139SRichard Marian Thomaiyar pwmp.padsize = pwctextlen - writtensize;
548216f2139SRichard Marian Thomaiyar pwmp.macsize = maclen;
549216f2139SRichard Marian Thomaiyar
550216f2139SRichard Marian Thomaiyar // Write the meta password structure, followed by hash, iv, encrypted
551216f2139SRichard Marian Thomaiyar // data & mac.
552216f2139SRichard Marian Thomaiyar if (fwrite(&pwmp, 1, sizeof(pwmp), pwfile) != sizeof(pwmp)) {
553216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in writing meta data");
554216f2139SRichard Marian Thomaiyar err = 1;
555216f2139SRichard Marian Thomaiyar }
556216f2139SRichard Marian Thomaiyar if (fwrite(hash, 1, pwmp.hashsize, pwfile) != pwmp.hashsize) {
557216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in writing hash data");
558216f2139SRichard Marian Thomaiyar err = 1;
559216f2139SRichard Marian Thomaiyar }
560216f2139SRichard Marian Thomaiyar if (fwrite(iv, 1, pwmp.ivsize, pwfile) != pwmp.ivsize) {
561216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in writing IV data");
562216f2139SRichard Marian Thomaiyar err = 1;
563216f2139SRichard Marian Thomaiyar }
564216f2139SRichard Marian Thomaiyar if (fwrite(pwctext, 1, pwctextlen, pwfile) != pwctextlen) {
565216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in encrypted data");
566216f2139SRichard Marian Thomaiyar err = 1;
567216f2139SRichard Marian Thomaiyar }
568216f2139SRichard Marian Thomaiyar if (fwrite(mac, 1, maclen, pwfile) != maclen) {
569216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "Error in writing MAC");
570216f2139SRichard Marian Thomaiyar err = 1;
571216f2139SRichard Marian Thomaiyar }
572216f2139SRichard Marian Thomaiyar
573216f2139SRichard Marian Thomaiyar free(pwctext);
574216f2139SRichard Marian Thomaiyar free(pwptext);
575216f2139SRichard Marian Thomaiyar
576216f2139SRichard Marian Thomaiyar if (fflush(pwfile) || fsync(fileno(pwfile))) {
577216f2139SRichard Marian Thomaiyar pam_syslog(
578216f2139SRichard Marian Thomaiyar pamh, LOG_DEBUG,
579216f2139SRichard Marian Thomaiyar "fflush or fsync error writing entries to special file: %s",
580216f2139SRichard Marian Thomaiyar tempfilename);
581216f2139SRichard Marian Thomaiyar err = 1;
582216f2139SRichard Marian Thomaiyar }
583216f2139SRichard Marian Thomaiyar
584216f2139SRichard Marian Thomaiyar if (fclose(pwfile)) {
585216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
586216f2139SRichard Marian Thomaiyar "fclose error writing entries to special file: %s",
587216f2139SRichard Marian Thomaiyar tempfilename);
588216f2139SRichard Marian Thomaiyar err = 1;
589216f2139SRichard Marian Thomaiyar }
590216f2139SRichard Marian Thomaiyar
591216f2139SRichard Marian Thomaiyar done:
592216f2139SRichard Marian Thomaiyar if (!err) {
593216f2139SRichard Marian Thomaiyar // Step 5: Rename the temporary file as special password file.
594216f2139SRichard Marian Thomaiyar if (!rename(tempfilename, filename)) {
595216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG,
596216f2139SRichard Marian Thomaiyar "password changed for %s in special file",
597216f2139SRichard Marian Thomaiyar forwho);
598216f2139SRichard Marian Thomaiyar } else {
599216f2139SRichard Marian Thomaiyar err = 1;
600216f2139SRichard Marian Thomaiyar }
601216f2139SRichard Marian Thomaiyar }
602216f2139SRichard Marian Thomaiyar
603216f2139SRichard Marian Thomaiyar // Clear out the key buff.
604216f2139SRichard Marian Thomaiyar memset(keybuff, 0, keybuffsize);
605216f2139SRichard Marian Thomaiyar
606216f2139SRichard Marian Thomaiyar if (!err) {
607216f2139SRichard Marian Thomaiyar return PAM_SUCCESS;
608216f2139SRichard Marian Thomaiyar } else {
609216f2139SRichard Marian Thomaiyar unlink(tempfilename);
610216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_ERR;
611216f2139SRichard Marian Thomaiyar }
612216f2139SRichard Marian Thomaiyar }
613216f2139SRichard Marian Thomaiyar
614216f2139SRichard Marian Thomaiyar /* Password Management API's */
615216f2139SRichard Marian Thomaiyar
616216f2139SRichard Marian Thomaiyar /**
617216f2139SRichard Marian Thomaiyar * @brief pam_sm_chauthtok API
618216f2139SRichard Marian Thomaiyar * Function which will be called for pam_chauthtok() calls.
619216f2139SRichard Marian Thomaiyar *
620216f2139SRichard Marian Thomaiyar * @param[in] pamh - pam handle
621216f2139SRichard Marian Thomaiyar * @param[in] flags - pam calls related flags
622216f2139SRichard Marian Thomaiyar * @param[in] argc - argument counts / options
623216f2139SRichard Marian Thomaiyar * @param[in] argv - array of arguments / options
624216f2139SRichard Marian Thomaiyar * @return - PAM_SUCCESS for success, others for failure
625216f2139SRichard Marian Thomaiyar */
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)626216f2139SRichard Marian Thomaiyar int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
627216f2139SRichard Marian Thomaiyar {
628216f2139SRichard Marian Thomaiyar int retval = -1;
629216f2139SRichard Marian Thomaiyar const void *item = NULL;
630216f2139SRichard Marian Thomaiyar const char *user = NULL;
631216f2139SRichard Marian Thomaiyar const char *pass_new = NULL, *pass_old = NULL;
632216f2139SRichard Marian Thomaiyar const char *spec_grp_name =
633216f2139SRichard Marian Thomaiyar get_option(pamh, "spec_grp_name", argc, argv);
634216f2139SRichard Marian Thomaiyar const char *spec_pass_file =
635216f2139SRichard Marian Thomaiyar get_option(pamh, "spec_pass_file", argc, argv);
636216f2139SRichard Marian Thomaiyar const char *key_file = get_option(pamh, "key_file", argc, argv);
637216f2139SRichard Marian Thomaiyar
638216f2139SRichard Marian Thomaiyar if (spec_grp_name == NULL || key_file == NULL) {
639216f2139SRichard Marian Thomaiyar return PAM_IGNORE;
640216f2139SRichard Marian Thomaiyar }
641216f2139SRichard Marian Thomaiyar if (flags & PAM_PRELIM_CHECK) {
642216f2139SRichard Marian Thomaiyar // send success to verify other stacked modules prelim check.
643216f2139SRichard Marian Thomaiyar return PAM_SUCCESS;
644216f2139SRichard Marian Thomaiyar }
645216f2139SRichard Marian Thomaiyar
646216f2139SRichard Marian Thomaiyar retval = pam_get_user(pamh, &user, NULL);
647216f2139SRichard Marian Thomaiyar if (retval != PAM_SUCCESS) {
648216f2139SRichard Marian Thomaiyar return retval;
649216f2139SRichard Marian Thomaiyar }
650216f2139SRichard Marian Thomaiyar
651216f2139SRichard Marian Thomaiyar // get already read password by the stacked pam module
652216f2139SRichard Marian Thomaiyar // Note: If there are no previous stacked pam module which read
653216f2139SRichard Marian Thomaiyar // the new password, then return with AUTHTOK_ERR
654216f2139SRichard Marian Thomaiyar
655216f2139SRichard Marian Thomaiyar retval = pam_get_item(pamh, PAM_AUTHTOK, &item);
656216f2139SRichard Marian Thomaiyar if (retval != PAM_SUCCESS || item == NULL) {
657216f2139SRichard Marian Thomaiyar return PAM_AUTHTOK_ERR;
658216f2139SRichard Marian Thomaiyar }
659216f2139SRichard Marian Thomaiyar pass_new = item;
660216f2139SRichard Marian Thomaiyar
661216f2139SRichard Marian Thomaiyar struct group *grp;
662216f2139SRichard Marian Thomaiyar int spec_grp_usr = 0;
663216f2139SRichard Marian Thomaiyar // Verify whether the user belongs to special group.
664216f2139SRichard Marian Thomaiyar grp = pam_modutil_getgrnam(pamh, spec_grp_name);
665216f2139SRichard Marian Thomaiyar if (grp != NULL) {
666216f2139SRichard Marian Thomaiyar while (*(grp->gr_mem) != NULL) {
667216f2139SRichard Marian Thomaiyar if (strcmp(user, *grp->gr_mem) == 0) {
668216f2139SRichard Marian Thomaiyar spec_grp_usr = 1;
669216f2139SRichard Marian Thomaiyar break;
670216f2139SRichard Marian Thomaiyar }
671216f2139SRichard Marian Thomaiyar (grp->gr_mem)++;
672216f2139SRichard Marian Thomaiyar }
673216f2139SRichard Marian Thomaiyar }
674216f2139SRichard Marian Thomaiyar
675216f2139SRichard Marian Thomaiyar pam_syslog(pamh, LOG_DEBUG, "User belongs to special grp: %x",
676216f2139SRichard Marian Thomaiyar spec_grp_usr);
677216f2139SRichard Marian Thomaiyar
678216f2139SRichard Marian Thomaiyar if (spec_grp_usr) {
679216f2139SRichard Marian Thomaiyar // verify the new password is acceptable.
680a80864a7SJiaqing Zhao size_t pass_len = strlen(pass_new);
681a80864a7SJiaqing Zhao size_t user_len = strlen(user);
6829e7627a5SPatrick Williams if (pass_len > MAX_SPEC_GRP_PASS_LENGTH ||
6839e7627a5SPatrick Williams user_len > MAX_SPEC_GRP_USER_LENGTH) {
6849e7627a5SPatrick Williams pam_syslog(pamh, LOG_ERR,
6859e7627a5SPatrick Williams "Password length (%zu) / User name length "
6869e7627a5SPatrick Williams "(%zu) is not acceptable for IPMI",
687a80864a7SJiaqing Zhao pass_len, user_len);
688a80864a7SJiaqing Zhao pass_new = pass_old = NULL;
689e3771e85SJiaqing Zhao return PAM_AUTHTOK_ERR;
690216f2139SRichard Marian Thomaiyar }
691216f2139SRichard Marian Thomaiyar if (spec_pass_file == NULL) {
692216f2139SRichard Marian Thomaiyar spec_pass_file = DEFAULT_SPEC_PASS_FILE;
693216f2139SRichard Marian Thomaiyar pam_syslog(
694216f2139SRichard Marian Thomaiyar pamh, LOG_ERR,
695216f2139SRichard Marian Thomaiyar "Using default special password file name :%s",
696216f2139SRichard Marian Thomaiyar spec_pass_file);
697216f2139SRichard Marian Thomaiyar }
698bb71716bSVernon Mauery if ((retval = lock_pwdf())) {
6999565abd6SPatrick Venture pam_syslog(pamh, LOG_ERR,
700216f2139SRichard Marian Thomaiyar "Failed to lock the passwd file");
701216f2139SRichard Marian Thomaiyar return retval;
702216f2139SRichard Marian Thomaiyar }
703216f2139SRichard Marian Thomaiyar retval = update_pass_special_file(
704216f2139SRichard Marian Thomaiyar pamh, key_file, spec_pass_file, user, pass_new);
705216f2139SRichard Marian Thomaiyar unlock_pwdf();
706216f2139SRichard Marian Thomaiyar return retval;
707216f2139SRichard Marian Thomaiyar }
708216f2139SRichard Marian Thomaiyar
709216f2139SRichard Marian Thomaiyar return PAM_SUCCESS;
710216f2139SRichard Marian Thomaiyar }
711216f2139SRichard Marian Thomaiyar
712216f2139SRichard Marian Thomaiyar /* end of module definition */
713