xref: /openbmc/pam-ipmi/src/pam_ipmisave/pam_ipmisave.c (revision d9c11abd92db59a4559c71eadbb8e07fcf09dcd4)
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