1 /*
2  * PAM authentication routines.
3  */
4 
5 #include "params.h"
6 
7 #if (AUTH_PAM || AUTH_PAM_USERPASS) && !VIRTUAL_ONLY
8 
9 #define _XOPEN_SOURCE 4
10 #define _XOPEN_SOURCE_EXTENDED
11 #define _XOPEN_VERSION 4
12 #define _XPG4_2
13 #include <string.h>
14 #include <stdlib.h>
15 #include <pwd.h>
16 #include <sys/types.h>
17 
18 #include <security/pam_appl.h>
19 
20 #if (defined(__sun) || defined(__hpux)) && \
21     !defined(LINUX_PAM) && !defined(_OPENPAM)
22 #define lo_const			/* Sun's PAM doesn't use const here */
23 #else
24 #define lo_const			const
25 #endif
26 typedef lo_const void *pam_item_t;
27 
28 #if USE_LIBPAM_USERPASS
29 #include <security/pam_userpass.h>
30 
31 #else
32 
33 #if AUTH_PAM_USERPASS
34 #include <security/pam_client.h>
35 
36 #ifndef PAM_BP_RCONTROL
37 /* Linux-PAM prior to 0.74 */
38 #define PAM_BP_RCONTROL	PAM_BP_CONTROL
39 #define PAM_BP_WDATA	PAM_BP_DATA
40 #define PAM_BP_RDATA	PAM_BP_DATA
41 #endif
42 
43 #define USERPASS_AGENT_ID		"userpass"
44 #define USERPASS_AGENT_ID_LENGTH	8
45 
46 #define USERPASS_USER_MASK		0x03
47 #define USERPASS_USER_REQUIRED		1
48 #define USERPASS_USER_KNOWN		2
49 #define USERPASS_USER_FIXED		3
50 #endif
51 
52 typedef struct {
53 	char *user;
54 	char *pass;
55 } pam_userpass_t;
56 
pam_userpass_conv(int num_msg,lo_const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)57 static int pam_userpass_conv(int num_msg, lo_const struct pam_message **msg,
58 	struct pam_response **resp, void *appdata_ptr)
59 {
60 	pam_userpass_t *userpass = (pam_userpass_t *)appdata_ptr;
61 #if AUTH_PAM_USERPASS
62 	pamc_bp_t prompt;
63 	const char *input;
64 	char *output;
65 	char flags;
66 
67 	if (num_msg != 1 || msg[0]->msg_style != PAM_BINARY_PROMPT)
68 		return PAM_CONV_ERR;
69 
70 	prompt = (pamc_bp_t)msg[0]->msg;
71 	input = PAM_BP_RDATA(prompt);
72 
73 	if (PAM_BP_RCONTROL(prompt) != PAM_BPC_SELECT ||
74 	    strncmp(input, USERPASS_AGENT_ID "/", USERPASS_AGENT_ID_LENGTH + 1))
75 		return PAM_CONV_ERR;
76 
77 	flags = input[USERPASS_AGENT_ID_LENGTH + 1];
78 	input += USERPASS_AGENT_ID_LENGTH + 1 + 1;
79 
80 	if ((flags & USERPASS_USER_MASK) == USERPASS_USER_FIXED &&
81 	    strcmp(input, userpass->user))
82 		return PAM_CONV_AGAIN;
83 
84 	if (!(*resp = malloc(sizeof(struct pam_response))))
85 		return PAM_CONV_ERR;
86 
87 	prompt = NULL;
88 	PAM_BP_RENEW(&prompt, PAM_BPC_DONE,
89 		strlen(userpass->user) + 1 + strlen(userpass->pass));
90 	output = PAM_BP_WDATA(prompt);
91 
92 	strcpy(output, userpass->user);
93 	output += strlen(output) + 1;
94 	memcpy(output, userpass->pass, strlen(userpass->pass));
95 
96 	(*resp)[0].resp_retcode = 0;
97 	(*resp)[0].resp = (char *)prompt;
98 #else
99 	char *string;
100 	int i;
101 
102 #if (defined(__sun) || defined(__hpux)) && \
103     !defined(LINUX_PAM) && !defined(_OPENPAM)
104 /*
105  * Insist on only one message per call because of differences in the
106  * layout of the "msg" parameter.  It can be an array of pointers to
107  * struct pam_message (Linux-PAM, OpenPAM) or a pointer to an array of
108  * struct pam_message (Sun PAM).  We only fully support the former.
109  */
110 	if (num_msg != 1)
111 		return PAM_CONV_ERR;
112 #endif
113 
114 	if (!(*resp = malloc(num_msg * sizeof(struct pam_response))))
115 		return PAM_CONV_ERR;
116 
117 	for (i = 0; i < num_msg; i++) {
118 		string = NULL;
119 		switch (msg[i]->msg_style) {
120 		case PAM_PROMPT_ECHO_ON:
121 			string = userpass->user;
122 		case PAM_PROMPT_ECHO_OFF:
123 			if (!string)
124 				string = userpass->pass;
125 			if (!(string = strdup(string)))
126 				break;
127 		case PAM_ERROR_MSG:
128 		case PAM_TEXT_INFO:
129 			(*resp)[i].resp_retcode = PAM_SUCCESS;
130 			(*resp)[i].resp = string;
131 			continue;
132 		}
133 
134 		while (--i >= 0) {
135 			if (!(*resp)[i].resp) continue;
136 			memset((*resp)[i].resp, 0, strlen((*resp)[i].resp));
137 			free((*resp)[i].resp);
138 			(*resp)[i].resp = NULL;
139 		}
140 
141 		free(*resp);
142 		*resp = NULL;
143 
144 		return PAM_CONV_ERR;
145 	}
146 #endif
147 
148 	return PAM_SUCCESS;
149 }
150 #endif /* USE_LIBPAM_USERPASS */
151 
is_user_known(char * user)152 static int is_user_known(char *user)
153 {
154 	struct passwd *pw;
155 
156 	if ((pw = getpwnam(user)))
157 		memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
158 	endpwent();
159 
160 	return pw != NULL;
161 }
162 
auth_userpass(char * user,char * pass,int * known)163 struct passwd *auth_userpass(char *user, char *pass, int *known)
164 {
165 	struct passwd *pw;
166 	pam_handle_t *pamh;
167 	pam_userpass_t userpass;
168 	struct pam_conv conv = {pam_userpass_conv, &userpass};
169 	pam_item_t item;
170 	lo_const char *template;
171 	int status;
172 
173 	*known = 0;
174 
175 	userpass.user = user;
176 	userpass.pass = pass;
177 
178 	if (pam_start(AUTH_PAM_SERVICE, user, &conv, &pamh) != PAM_SUCCESS) {
179 		*known = is_user_known(user);
180 		return NULL;
181 	}
182 
183 	if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
184 		pam_end(pamh, status);
185 		*known = is_user_known(user);
186 		return NULL;
187 	}
188 
189 	if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
190 		pam_end(pamh, status);
191 		*known = is_user_known(user);
192 		return NULL;
193 	}
194 
195 	status = pam_get_item(pamh, PAM_USER, &item);
196 	if (status != PAM_SUCCESS) {
197 		pam_end(pamh, status);
198 		*known = is_user_known(user);
199 		return NULL;
200 	}
201 	template = item;
202 
203 	template = strdup(template);
204 
205 	if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS || !template) {
206 		*known = is_user_known(user);
207 		return NULL;
208 	}
209 
210 	if ((pw = getpwnam(template))) {
211 		memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
212 		*known = 1;
213 	}
214 	endpwent();
215 
216 	return pw;
217 }
218 
219 #endif
220