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