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