1
2 #include <pam_appl.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10
11
12 #define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \
13 (((unsigned char*) (s))[1]))
14
15
16 #define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
17 ((unsigned char*)(s))[1] = (i) & 0xff;}
18
19 #ifndef D
20 /*#define D(str) fprintf(stderr, (str)) */
21 #define D(str)
22 #endif
23
read_fill(int fd,unsigned char * buf,int len)24 static int read_fill(int fd, unsigned char *buf, int len)
25 {
26 int i, got = 0;
27
28 do {
29 if ((i = read(fd, buf+got, len-got)) <= 0) {
30 if (i == 0) return got;
31 if (errno != EINTR)
32 return got;
33 i = 0;
34 }
35 got += i;
36 } while (got < len);
37 return (len);
38 }
39
40
41
write_fill(int fd,char * buf,int len)42 static int write_fill(int fd, char *buf, int len)
43 {
44 int i, done = 0;
45
46 do {
47 if ((i = write(fd, buf+done, len-done)) < 0) {
48 if (errno != EINTR)
49 return (i);
50 i = 0;
51 }
52 done += i;
53 } while (done < len);
54 return (len);
55 }
56
57
58 #if 0
59 /*
60 * These functions are for binary prompt manipulation.
61 * The manner in which a binary prompt is processed is application
62 * specific, so these function pointers are provided and can be
63 * initialized by the application prior to the conversation function
64 * being used.
65 */
66
67 static void pam_misc_conv_delete_binary(void *appdata,
68 pamc_bp_t *delete_me)
69 {
70 PAM_BP_RENEW(delete_me, 0, 0);
71 }
72
73 int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL;
74 void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p)
75 = pam_misc_conv_delete_binary;
76 #endif
77
78 /*
79 * This conversation function is supposed to be a generic PAM one.
80 * Unfortunately, it is _not_ completely compatible with the Solaris PAM
81 * codebase.
82 *
83 * Namely, for msgm's that contain multiple prompts, this function
84 * interprets "const struct pam_message **msgm" as equivalent to
85 * "const struct pam_message *msgm[]". The Solaris module
86 * implementation interprets the **msgm object as a pointer to a
87 * pointer to an array of "struct pam_message" objects (that is, a
88 * confusing amount of pointer indirection).
89 */
90
misc_conv(int num_msg,const struct pam_message ** msgm,struct pam_response ** response,void * appdata_ptr)91 int misc_conv(int num_msg, const struct pam_message **msgm,
92 struct pam_response **response, void *appdata_ptr)
93 {
94 int count=0;
95 struct pam_response *reply;
96
97 if (num_msg <= 0)
98 return PAM_CONV_ERR;
99
100 D(("allocating empty response structure array."));
101
102 reply = (struct pam_response *) calloc(num_msg,
103 sizeof(struct pam_response));
104 if (reply == NULL) {
105 D(("no memory for responses"));
106 return PAM_CONV_ERR;
107 }
108
109 D(("entering conversation function."));
110
111 for (count=0; count < num_msg; ++count) {
112 char *string=NULL;
113
114 switch (msgm[count]->msg_style) {
115 case PAM_PROMPT_ECHO_OFF:
116 string = (char*)appdata_ptr;
117 break;
118 case PAM_PROMPT_ECHO_ON:
119 string = (char*)appdata_ptr;
120 break;
121 case PAM_ERROR_MSG:
122 if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) {
123 goto failed_conversation;
124 }
125 break;
126 case PAM_TEXT_INFO:
127 if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) {
128 goto failed_conversation;
129 }
130 break;
131 #if 0
132 case PAM_BINARY_PROMPT:
133 {
134 pamc_bp_t binary_prompt = NULL;
135
136 if (!msgm[count]->msg || !pam_binary_handler_fn) {
137 goto failed_conversation;
138 }
139
140 PAM_BP_RENEW(&binary_prompt,
141 PAM_BP_RCONTROL(msgm[count]->msg),
142 PAM_BP_LENGTH(msgm[count]->msg));
143 PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg),
144 PAM_BP_RDATA(msgm[count]->msg));
145
146 if (pam_binary_handler_fn(appdata_ptr,
147 &binary_prompt) != PAM_SUCCESS
148 || (binary_prompt == NULL)) {
149 goto failed_conversation;
150 }
151 string = (char *) binary_prompt;
152 binary_prompt = NULL;
153
154 break;
155 }
156 #endif
157 default:
158 fprintf(stderr, "erroneous conversation (%d)\n"
159 ,msgm[count]->msg_style);
160 goto failed_conversation;
161 }
162
163 if (string) { /* must add to reply array */
164 /* add string to list of responses */
165
166 reply[count].resp_retcode = 0;
167 reply[count].resp = string;
168 string = NULL;
169 }
170 }
171
172 *response = reply;
173 reply = NULL;
174
175 return PAM_SUCCESS;
176
177 failed_conversation:
178
179 D(("the conversation failed"));
180
181 if (reply) {
182 for (count=0; count<num_msg; ++count) {
183 if (reply[count].resp == NULL) {
184 continue;
185 }
186 switch (msgm[count]->msg_style) {
187 case PAM_PROMPT_ECHO_ON:
188 case PAM_PROMPT_ECHO_OFF:
189 #if 0
190 _pam_overwrite(reply[count].resp);
191 #endif
192 free(reply[count].resp);
193 break;
194 #if 0
195 case PAM_BINARY_PROMPT:
196 pam_binary_handler_free(appdata_ptr,
197 (pamc_bp_t *) &reply[count].resp);
198 break;
199 #endif
200 case PAM_ERROR_MSG:
201 case PAM_TEXT_INFO:
202 /* should not actually be able to get here... */
203 free(reply[count].resp);
204 }
205 reply[count].resp = NULL;
206 }
207 /* forget reply too */
208 free(reply);
209 reply = NULL;
210 }
211
212 return PAM_CONV_ERR;
213 }
214
215
216
217
218
219
220 static struct pam_conv conv = {
221 misc_conv,
222 NULL
223 };
224
werr(pam_handle_t * pamh,int sid,int ecode,char * phase)225 static void werr(pam_handle_t *pamh, int sid, int ecode, char *phase)
226 {
227 char buf[BUFSIZ];
228 int len;
229
230 sprintf(&buf[2], "pam %d no %s %s",
231 sid, phase, pam_strerror(pamh, ecode));
232 len = strlen(&buf[2]);
233 put_int16(len, &buf[0]);
234 if (write_fill(1, buf, len+2) != len+2)
235 exit(1);
236 }
237
238
wok(int sid)239 static void wok(int sid)
240 {
241 char buf[BUFSIZ];
242 int len;
243
244 sprintf(&buf[2], "pam %d yes", sid);
245 len = strlen(&buf[2]);
246 put_int16(len, &buf[0]);
247 if (write_fill(1, buf, len+2) != len+2)
248 exit(1);
249 }
250
wstart()251 static void wstart()
252 {
253 char buf[5];
254
255
256 sprintf(&buf[2], "ok");
257 put_int16(2, &buf[0]);
258 if (write_fill(1, buf, 4) != 4) {
259 exit(1);
260 }
261 }
262
263
264 struct session {
265 pam_handle_t *pamh;
266 int sid;
267 int session_mode;
268 struct session *next;
269 };
270
271 static struct session *sessions = NULL;
272
del_session(struct session ** sp,int sid)273 static struct session *del_session(struct session **sp, int sid)
274 {
275
276 struct session *tmp;
277
278 if (*sp == NULL) return NULL;
279 if ((*sp)->sid == sid) {
280 tmp = *sp;
281 *sp = tmp->next;
282 return tmp;
283 }
284 tmp = (*sp)->next;
285 while (tmp != NULL) {
286 if (tmp->sid == sid) {
287 (*sp)->next = tmp->next;
288 return tmp;
289 }
290 sp = &((*sp)->next);
291 tmp = tmp->next;
292 }
293 return NULL;
294 }
295
296
do_auth(char * service,char * user,char * pwd,char * mode,int sid)297 static void do_auth(char *service, char*user, char*pwd, char* mode, int sid)
298 {
299 pam_handle_t *pamh=NULL;
300 int retval;
301 struct session *sessp;
302
303 conv.appdata_ptr = (void*)strdup(pwd);
304 retval = pam_start(service, user, &conv, &pamh);
305
306 if (retval != PAM_SUCCESS) {
307 werr(pamh, sid, retval, "start");
308 return;
309 }
310 pam_set_item(pamh, PAM_RUSER, user);
311
312 retval = pam_authenticate(pamh, 0);
313 if (retval != PAM_SUCCESS) {
314 werr(pamh, sid, retval, "auth");
315 return;
316 }
317 if (mode[0] == 'A') {
318 retval = pam_acct_mgmt(pamh, 0);
319 if (retval != PAM_SUCCESS) {
320 werr(pamh, sid, retval, "accounting");
321 return;
322 }
323 /*fprintf(stderr, "did ok acct \n\r");*/
324 }
325 if (mode[1] == 'S') {
326 retval = pam_open_session(pamh, 0);
327 if (retval != PAM_SUCCESS) {
328 werr(pamh, sid, retval, "session");
329 return;
330 }
331 /*fprintf(stderr, "did ok open sess \n\r"); */
332 }
333 if ((sessp = malloc(sizeof(struct session))) == NULL) {
334 werr(pamh, sid, -1, "malloc");
335 return;
336 }
337 if (mode[1] == 'S')
338 sessp->session_mode = 1;
339 else
340 sessp->session_mode = 0;
341 sessp->sid = sid;
342 sessp->pamh = pamh;
343 sessp->next = sessions;
344 sessions = sessp;
345
346 wok(sid);
347 }
348
349
main(int argc,char * argv[])350 int main(int argc, char *argv[])
351 {
352 unsigned char lb[2];
353 unsigned char buf[BUFSIZ];
354 char *user;
355 char *pwd;
356 char *mode;
357 int sid;
358 int rval;
359 struct session *sessp;
360
361 // test clause
362 if (argc == 4 ) {
363 /* ./epam authmodule user passwd */
364 printf("testing service=%s u=%s pwd=%s\n", argv[1],argv[2], argv[3]);
365 do_auth(argv[1], argv[2], argv[3], "AS", 33);
366 exit(0);
367 }
368 wstart();
369 while (1) {
370 if (read_fill(0, lb, 2) != 2)
371 exit(1);
372 rval = get_int16(lb);
373 if (read_fill(0, buf, rval) != rval)
374 exit(1);
375 switch (buf[0]) {
376 case 'a':
377 // auth a user
378 user = (char *)&buf[1];
379 pwd = user + strlen(user) + 1;
380 mode= pwd + strlen(pwd) + 1;
381 sid = atoi(mode + strlen(mode) + 1);
382
383 do_auth(argv[1], user, pwd, mode, sid);
384 break;
385 case 'c':
386 // close session
387 sid = atoi((char *)&buf[1]);
388 if ((sessp = del_session(&sessions, sid)) == NULL) {
389 fprintf(stderr, "Couldn't find session %d\r\n", sid);
390 break;
391 }
392 if (sessp->session_mode == 1) {
393 pam_close_session(sessp->pamh, 0);
394 /*fprintf(stderr, "did ok close sess \n\r");*/
395 }
396 pam_end(sessp->pamh, PAM_SUCCESS);
397 free(sessp);
398 break;
399 default:
400 fprintf(stderr, "Bad op \n\r");
401 }
402 }
403 }
404
405
406