1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include <syslog.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <string.h>
22 
23 #include <security/pam_ext.h>
24 #include <security/pam_modules.h>
25 #include <security/pam_modutil.h>
26 
27 #define MAX_SPEC_GRP_PASS_LENGTH 20
28 #define MAX_SPEC_GRP_USER_LENGTH 16
29 
30 
31 /*
32  * This module is intended to verify special group user password matches the
33  * restrictions needed.
34  *
35  * Note: Other than for pam_chauthtok(), pam_ipmicheck module should not be
36  * used for other purpose like authentication, session & account management.
37  * This module has to be used along with pam_ipmisave module, which will save
38  * the passwords of the special group users.
39  */
40 
41 
42 static const char *get_option(const pam_handle_t *pamh, const char *option,
43 			      int argc, const char **argv)
44 {
45 	int i = 0;
46 	size_t len = strlen(option);
47 
48 	for (i = 0; i < argc; ++i) {
49 		if (strncmp(option, argv[i], len) == 0) {
50 			if (argv[i][len] == '=') {
51 				return &argv[i][len + 1];
52 			}
53 		}
54 	}
55 	return NULL;
56 }
57 
58 /* Password Management API's */
59 
60 int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
61 {
62 	int retval = -1;
63 	const void *item = NULL;
64 	const char *user = NULL;
65 	const char *pass_new = NULL, *pass_old = NULL;
66 	const char *spec_grp_name =
67 		get_option(pamh, "spec_grp_name", argc, argv);
68 
69 	pam_syslog(pamh, LOG_DEBUG, "Special group name is %s", spec_grp_name);
70 
71 	if (spec_grp_name == NULL) {
72 		return PAM_IGNORE;
73 	}
74 	if (flags & PAM_PRELIM_CHECK) {
75 		// send success to verify other stacked modules prelim check.
76 		pam_syslog(pamh, LOG_DEBUG, "PRELIM_CHECK Called");
77 		return PAM_SUCCESS;
78 	}
79 
80 	// Read new password.
81 	// Note: Subsequent modules must use stacked password option use_authtok
82 	retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass_new, NULL);
83 	if (retval != PAM_SUCCESS) {
84 		pam_syslog(pamh, LOG_ERR,
85 			   "password - unable to get new password");
86 		return retval;
87 	}
88 
89 	retval = pam_get_user(pamh, &user, NULL);
90 	if (retval != PAM_SUCCESS) {
91 		return retval;
92 	}
93 
94 	struct group *grp;
95 	int spec_grp_usr = 0;
96 	// Verify whether the user belongs to special group.
97 	grp = pam_modutil_getgrnam(pamh, spec_grp_name);
98 	if (grp != NULL) {
99 		while (*(grp->gr_mem) != NULL) {
100 			if (strcmp(user, *grp->gr_mem) == 0) {
101 				spec_grp_usr = 1;
102 				break;
103 			}
104 			(grp->gr_mem)++;
105 		}
106 	}
107 
108 	if (spec_grp_usr) {
109 		// verify the new password is acceptable.
110 		if (strlen(pass_new) > MAX_SPEC_GRP_PASS_LENGTH
111 		    || strlen(user) > MAX_SPEC_GRP_USER_LENGTH) {
112 			pam_syslog(
113 				pamh, LOG_ERR,
114 				"Password length (%x) / User name length (%x) not acceptable",
115 				strlen(pass_new), strlen(user));
116 			pass_new = pass_old = NULL;
117 			return PAM_AUTHTOK_ERR;
118 		}
119 	}
120 
121 	return PAM_SUCCESS;
122 }
123 
124 /* end of module definition */
125