Initial import to Tizen
[profile/ivi/python-PyPAM.git] / PAMmodule.c
1 /*
2  * PAMmodule.c
3  *
4  * Python PAM module
5  *
6  * Copyright (c) 1999, 2006 Rob Riggs and tummy.com, Ltd. All rights reserved.
7  * Released under GNU LGPL version 2.1.
8  */
9
10 static char revision[] = "$Id: PAMmodule.c,v 1.3 2007/04/18 03:55:11 rob Exp $";
11
12 #include <security/pam_appl.h>
13 #include <security/pam_misc.h>
14 #include <Python.h>
15 #include <stdio.h>
16 #include <dlfcn.h>
17
18 static PyObject *PyPAM_Error;
19
20 typedef struct {
21     PyObject_HEAD
22     struct pam_conv     *conv;
23     pam_handle_t        *pamh;
24     char                *service;
25     char                *user;
26     PyObject            *callback;
27     struct pam_response *response_data;
28     int                 response_len;
29     PyObject            *user_data;
30     void                *dlh1, *dlh2;
31 } PyPAMObject;
32
33 staticforward PyTypeObject PyPAMObject_Type;
34
35 static void PyPAM_Err(PyPAMObject *self, int result)
36 {
37     PyObject            *error;
38     const char          *err_msg;
39
40     err_msg = pam_strerror(self->pamh, result);
41     error = Py_BuildValue("(si)", err_msg, result);
42     Py_INCREF(PyPAM_Error);
43     PyErr_SetObject(PyPAM_Error, error);
44 }
45
46 static int PyPAM_conv(int num_msg, const struct pam_message **msg,
47     struct pam_response **resp, void *appdata_ptr)
48 {
49     PyObject                *args;
50
51     PyPAMObject* self = (PyPAMObject *) appdata_ptr;
52     if (self->callback == NULL)
53         return PAM_CONV_ERR;
54
55     Py_INCREF(self);
56
57     if (NULL != self->response_data) {
58         for (int i = 0; i < self->response_len; i++) {
59             free(self->response_data[0].resp);
60         }
61         free(self->response_data);
62         self->response_data = NULL;
63         self->response_len = 0;
64     }
65
66     PyObject* msgList = PyList_New(num_msg);
67     
68     for (int i = 0; i < num_msg; i++) {
69         PyList_SetItem(msgList, i,
70             Py_BuildValue("(si)", msg[i]->msg, msg[i]->msg_style));
71     }
72     
73     args = Py_BuildValue("(OO)", self, msgList);
74     PyObject* respList = PyEval_CallObject(self->callback, args);
75     Py_DECREF(args);
76     Py_DECREF(self);
77     
78     if (respList == NULL)
79         return PAM_CONV_ERR;
80
81     if (!PyList_Check(respList)) {
82         Py_DECREF(respList);
83         return PAM_CONV_ERR;
84     }
85     
86     *resp = (struct pam_response *) malloc(
87         PyList_Size(respList) * sizeof(struct pam_response));
88
89     struct pam_response* spr = *resp;
90     for (int i = 0; i < PyList_Size(respList); i++, spr++) {
91         PyObject* respTuple = PyList_GetItem(respList, i);
92         char* resp_text;
93         int resp_retcode = 0;
94         if (!PyArg_ParseTuple(respTuple, "si", &resp_text, &resp_retcode)) {
95             free(*resp);
96             Py_DECREF(respList);
97             return PAM_CONV_ERR;
98         }
99         spr->resp = strdup(resp_text);
100         spr->resp_retcode = resp_retcode;
101         Py_DECREF(respTuple);
102     }
103     
104     // Save this so we can free it later.
105     self->response_data = *resp;
106     self->response_len = PyList_Size(respList);
107
108     Py_DECREF(respList);
109     
110     return PAM_SUCCESS;
111 }
112
113 static struct pam_conv default_conv = {
114     misc_conv,
115     NULL
116 };
117
118 static struct pam_conv python_conv = {
119     PyPAM_conv,
120     NULL
121 };
122
123 static PyObject * PyPAM_pam(PyObject *self, PyObject *args)
124 {
125     PyPAMObject             *p;
126     struct pam_conv         *spc;
127
128     if (!PyArg_ParseTuple(args, "")) {
129         PyErr_SetString(PyExc_TypeError, "pam() takes no arguments");
130         return NULL;
131     }
132
133     PyPAMObject_Type.ob_type = &PyType_Type;
134     p = (PyPAMObject *) PyObject_NEW(PyPAMObject, &PyPAMObject_Type);
135
136     if ((spc = (struct pam_conv *) malloc(sizeof(struct pam_conv))) == NULL) {
137         PyErr_SetString(PyExc_MemoryError, "out of memory");
138         return NULL;
139     }
140
141     p->conv = spc;
142     p->pamh = NULL;
143     p->service = NULL;
144     p->user = NULL;
145     Py_INCREF(Py_None);
146     p->callback = Py_None;
147     p->response_data = NULL;
148     p->response_len = 0;
149     Py_INCREF(Py_None);
150     p->user_data = Py_None;
151     
152     p->dlh1 = dlopen("libpam.so", RTLD_LAZY | RTLD_GLOBAL);
153     p->dlh2 = dlopen("libpam_misc.so", RTLD_LAZY | RTLD_GLOBAL);
154
155     return (PyObject *) p;
156 }
157
158 static PyObject * PyPAM_start(PyObject *self, PyObject *args)
159 {
160     int                 result;
161     char                *service = NULL, *user = NULL;
162     PyObject            *callback = NULL;
163     PyPAMObject         *_self = (PyPAMObject *) self;
164
165     if (!PyArg_ParseTuple(args, "s|zO", &service, &user, &callback)) {
166         PyErr_SetString(PyExc_TypeError, "start(service, [user, [callback]])");
167         return NULL;
168     }
169
170     if (callback != NULL && !PyCallable_Check(callback)) {
171         PyErr_SetString(
172             PyExc_TypeError,
173             "the callback parameter must be a function"
174         );
175         return NULL;
176     }
177
178     if (service) _self->service = strdup(service);
179     if (user) _self->user = strdup(user);
180
181     Py_DECREF(_self->callback);
182     if (callback) {
183         Py_INCREF(callback);
184         _self->callback = callback;
185         memcpy(_self->conv, &python_conv, sizeof(struct pam_conv));
186         _self->conv->appdata_ptr = (void *) self;
187     } else {
188         Py_INCREF(Py_None);
189         _self->callback = Py_None;
190         memcpy(_self->conv, &default_conv, sizeof(struct pam_conv));
191     }
192
193     result = pam_start(_self->service, _self->user, _self->conv, &_self->pamh);
194
195     if (result != PAM_SUCCESS) {
196         PyPAM_Err(_self, result);
197         return NULL;
198     }
199
200     Py_INCREF(Py_None);
201
202     return Py_None;
203 }
204
205 static PyObject * PyPAM_authenticate(PyObject *self, PyObject *args)
206 {
207     int                    result, flags = 0;
208     PyPAMObject*           _self = (PyPAMObject*) self;
209     
210     if (!PyArg_ParseTuple(args, "|i", &flags)) {
211         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
212         return NULL;
213     }
214     
215     result = pam_authenticate(_self->pamh, flags);
216     
217     if (result != PAM_SUCCESS) {
218         PyPAM_Err(_self, result);
219         return NULL;
220     }
221
222     Py_INCREF(Py_None);
223     
224     return Py_None;
225 }
226
227 static PyObject * PyPAM_setcred(PyObject *self, PyObject *args)
228 {
229     int                    result, flags = 0;
230     PyPAMObject            *_self = (PyPAMObject *) self;
231     
232     if (!PyArg_ParseTuple(args, "i", &flags)) {
233         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
234         return NULL;
235     }
236     
237     result = pam_setcred(_self->pamh, flags);
238     
239     if (result != PAM_SUCCESS) {
240         PyErr_SetString(PyPAM_Error, "Not authenticated");
241         return NULL;
242     }
243
244     Py_INCREF(Py_None);
245     
246     return Py_None;
247 }
248
249 static PyObject * PyPAM_acct_mgmt(PyObject *self, PyObject *args)
250 {
251     int                    result, flags = 0;
252     PyPAMObject            *_self = (PyPAMObject *) self;
253     
254     if (!PyArg_ParseTuple(args, "|i", &flags)) {
255         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
256         return NULL;
257     }
258     
259     result = pam_acct_mgmt(_self->pamh, flags);
260     
261     if (result != PAM_SUCCESS) {
262         PyErr_SetString(PyPAM_Error, "Not authenticated");
263         return NULL;
264     }
265
266     Py_INCREF(Py_None);
267     
268     return Py_None;
269 }
270
271 static PyObject * PyPAM_chauthtok(PyObject *self, PyObject *args)
272 {
273     int                    result, flags = 0;
274     PyPAMObject            *_self = (PyPAMObject *) self;
275     
276     if (!PyArg_ParseTuple(args, "|i", &flags)) {
277         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
278         return NULL;
279     }
280     
281     result = pam_chauthtok(_self->pamh, flags);
282     
283     if (result != PAM_SUCCESS) {
284         PyErr_SetString(PyPAM_Error, "Not authenticated");
285         return NULL;
286     }
287
288     Py_INCREF(Py_None);
289     
290     return Py_None;
291 }
292
293 static PyObject * PyPAM_open_session(PyObject *self, PyObject *args)
294 {
295     int                    result, flags = 0;
296     PyPAMObject            *_self = (PyPAMObject *) self;
297     
298     if (!PyArg_ParseTuple(args, "|i", &flags)) {
299         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
300         return NULL;
301     }
302     
303     result = pam_open_session(_self->pamh, flags);
304     
305     if (result != PAM_SUCCESS) {
306         PyErr_SetString(PyPAM_Error, "Not authenticated");
307         return NULL;
308     }
309
310     Py_INCREF(Py_None);
311     
312     return Py_None;
313 }
314
315 static PyObject * PyPAM_close_session(PyObject *self, PyObject *args)
316 {
317     int                    result, flags = 0;
318     PyPAMObject            *_self = (PyPAMObject *) self;
319     
320     if (!PyArg_ParseTuple(args, "|i", &flags)) {
321         PyErr_SetString(PyExc_TypeError, "parameter must be integer");
322         return NULL;
323     }
324     
325     result = pam_close_session(_self->pamh, flags);
326     
327     if (result != PAM_SUCCESS) {
328         PyErr_SetString(PyPAM_Error, "Not authenticated");
329         return NULL;
330     }
331
332     Py_INCREF(Py_None);
333     
334     return Py_None;
335 }
336
337 static PyObject * PyPAM_set_item(PyObject *self, PyObject *args)
338 {
339     int                 result, item;
340     char                *s_val, *n_val;
341     PyObject            *o_val;
342     PyPAMObject         *_self = (PyPAMObject *) self;
343     
344     if (PyArg_ParseTuple(args, "is", &item, &s_val)) {
345         n_val = strdup(s_val);
346         if (item == PAM_USER)
347             _self->user = n_val;
348         if (item == PAM_SERVICE)
349             _self->service = n_val;
350         result = pam_set_item(_self->pamh, item, (void *) n_val);
351     } else {
352         // An error occured parsing the tuple.  Clear it.  Then try to parse
353         // it a different way.
354         PyErr_Clear();
355         if (PyArg_ParseTuple(args, "iO:set_callback", &item, &o_val)) {
356             if (item == PAM_CONV && !PyCallable_Check(o_val)) {
357                 PyErr_SetString(PyExc_TypeError, "parameter must be a function");
358                 return NULL;
359             } else {
360                 Py_XDECREF(_self->callback);
361                 _self->callback = o_val;
362                 Py_INCREF(_self->callback);
363                 memcpy(_self->conv, &python_conv, sizeof(struct pam_conv));
364                 _self->conv->appdata_ptr = (void *) self;
365                 result = pam_set_item(_self->pamh, item, (void *) _self->conv);
366             }
367         } else {
368             PyErr_SetString(PyExc_TypeError, "bad parameter");
369             return NULL;
370         }
371     }
372
373     if (result != PAM_SUCCESS) {
374         PyPAM_Err(_self, result);
375         return NULL;
376     }
377
378     Py_INCREF(Py_None);
379     
380     return Py_None;
381 }
382
383 static PyObject * PyPAM_get_item(PyObject *self, PyObject *args)
384 {
385     int                    result, item;
386     const void            *val;
387     PyObject            *retval;
388     PyPAMObject            *_self = (PyPAMObject *) self;
389     
390     if (!PyArg_ParseTuple(args, "i", &item)) {
391         PyErr_SetString(PyExc_TypeError, "bad parameter");
392         return NULL;
393     }
394     
395     result = pam_get_item(_self->pamh, item, &val);
396     
397     if (result != PAM_SUCCESS) {
398         PyPAM_Err(_self, result);
399         return NULL;
400     }
401     
402     if (item == PAM_CONV)
403         retval = Py_BuildValue("O:set_callback", val);
404     else
405         retval = Py_BuildValue("s", val);
406
407
408     return retval;
409 }
410
411 static PyObject * PyPAM_putenv(PyObject *self, PyObject *args)
412 {
413     int                    result;
414     char                *val;
415     PyPAMObject            *_self = (PyPAMObject *) self;
416     
417     if (!PyArg_ParseTuple(args, "s", &val)) {
418         PyErr_SetString(PyExc_TypeError, "parameter must be a string");
419         return NULL;
420     }
421     
422     result = pam_putenv(_self->pamh, val);
423     
424     if (result != PAM_SUCCESS) {
425         PyErr_SetString(PyPAM_Error, "Not authenticated");
426         return NULL;
427     }
428
429     Py_INCREF(Py_None);
430     
431     return Py_None;
432 }
433
434 static PyObject * PyPAM_getenv(PyObject *self, PyObject *args)
435 {
436     const char          *result, *val;
437     PyObject            *retval;
438     PyPAMObject         *_self = (PyPAMObject *) self;
439     
440     if (!PyArg_ParseTuple(args, "s", &val)) {
441         PyErr_SetString(PyExc_TypeError, "parameter must be a string");
442         return NULL;
443     }
444     
445     result = pam_getenv(_self->pamh, val);
446     
447     if (result == NULL) {
448         Py_INCREF(Py_None);
449         return Py_None;
450     }
451     
452     retval = Py_BuildValue("s", result);
453     
454     return retval;
455 }
456
457 static PyObject * PyPAM_getenvlist(PyObject *self, PyObject *args)
458 {
459     char                **result, *cp;
460     PyObject            *retval, *entry;
461     PyPAMObject            *_self = (PyPAMObject *) self;
462     
463     result = pam_getenvlist(_self->pamh);
464     
465     if (result == NULL) {
466         Py_INCREF(Py_None);
467         return Py_None;
468     }
469     
470     retval = PyList_New(0);
471     
472     while ((cp = *(result++)) != NULL) {
473         entry = Py_BuildValue("s", cp);
474         PyList_Append(retval, entry);
475         Py_DECREF(entry);
476     }
477     
478     return retval;
479 }
480
481 static PyObject * PyPAM_set_userdata(PyObject *self, PyObject *args)
482 {
483     PyPAMObject     *_self = (PyPAMObject *) self;
484     PyObject        *user_data;
485
486     if (!PyArg_ParseTuple(args, "O", &user_data)) {
487         PyErr_SetString(
488             PyExc_TypeError,
489             "set_userdata() expects exactly 1 argument"
490         );
491         return NULL;
492     }
493
494     Py_DECREF(_self->user_data);
495     Py_INCREF(user_data);
496     _self->user_data = user_data;
497
498     Py_INCREF(Py_None);
499     return Py_None;
500 }
501
502 static PyObject * PyPAM_get_userdata(PyObject *self, PyObject *args)
503 {
504     PyPAMObject     *_self = (PyPAMObject *) self;
505
506     if (!PyArg_ParseTuple(args, "")) {
507         PyErr_SetString(
508             PyExc_TypeError,
509             "get_userdata() takes no arguments"
510         );
511         return NULL;
512     }
513
514     Py_INCREF(_self->user_data);
515     return _self->user_data;
516 }
517
518 static PyMethodDef PyPAMObject_Methods[] = {
519     {"start", PyPAM_start, METH_VARARGS, NULL},
520     {"authenticate", PyPAM_authenticate, METH_VARARGS, NULL},
521     {"setcred", PyPAM_setcred, METH_VARARGS, NULL},
522     {"acct_mgmt", PyPAM_acct_mgmt, METH_VARARGS, NULL},
523     {"chauthtok", PyPAM_chauthtok, METH_VARARGS, NULL},
524     {"open_session", PyPAM_open_session, METH_VARARGS, NULL},
525     {"close_session", PyPAM_close_session, METH_VARARGS, NULL},
526     {"set_item", PyPAM_set_item, METH_VARARGS, NULL},
527     {"get_item", PyPAM_get_item, METH_VARARGS, NULL},
528     {"putenv", PyPAM_putenv, METH_VARARGS, NULL},
529     {"getenv", PyPAM_getenv, METH_VARARGS, NULL},
530     {"getenvlist", PyPAM_getenvlist, METH_VARARGS, NULL},
531     {"set_userdata", PyPAM_set_userdata, METH_VARARGS, NULL},
532     {"get_userdata", PyPAM_get_userdata, METH_VARARGS, NULL},
533     {NULL, NULL, 0, NULL}
534 };
535
536 static void PyPAM_dealloc(PyPAMObject *self)
537 {
538     free(self->service);
539     free(self->user);
540     free(self->conv);
541     pam_end(self->pamh, PAM_SUCCESS);
542     dlclose(self->dlh2);
543     dlclose(self->dlh1);
544     PyMem_DEL(self);
545 }
546
547 static PyObject * PyPAM_getattr(PyPAMObject *self, char *name)
548 {
549     return Py_FindMethod(PyPAMObject_Methods, (PyObject *) self, name);
550 }
551
552 static PyObject * PyPAM_repr(PyPAMObject *self)
553 {
554     char                buf[1024];
555     
556     snprintf(buf, 1024, "<pam object, service=\"%s\", user=\"%s\", conv=%p, pamh=%p>",
557         self->service, self->user, self->conv, self->pamh);
558     return PyString_FromString(buf);
559 }
560
561 static PyTypeObject PyPAMObject_Type = {
562     PyObject_HEAD_INIT(0)    /* Must fill in type value later */
563     0,
564     "pam",
565     sizeof(PyPAMObject),
566     0,
567     (destructor)PyPAM_dealloc,        /*tp_dealloc*/
568     0,        /*tp_print*/
569     (getattrfunc)PyPAM_getattr,        /*tp_getattr*/
570     0,        /*tp_setattr*/
571     0,        /*tp_compare*/
572     (reprfunc)PyPAM_repr,            /*tp_repr*/
573     0,        /*tp_as_number*/
574     0,        /*tp_as_sequence*/
575     0,        /*tp_as_mapping*/
576 };
577
578 static PyMethodDef PyPAM_Methods[] = {
579     {"pam", PyPAM_pam, METH_VARARGS, NULL},
580     {NULL, NULL, 0, NULL}
581 };
582
583 static char PyPAMObject_doc[] = "";
584
585 /* Convenience routine to export an integer value.
586  *
587  * Errors are silently ignored, for better or for worse...
588  * Happily borrowed from Python's socketmodule.c
589  */
590 static void insint(PyObject *d, char *name, int value)
591 {
592     PyObject*        v = PyInt_FromLong((long) value);
593
594     if (!v || PyDict_SetItemString(d, name, v))
595         PyErr_Clear();
596
597     Py_XDECREF(v);
598 }
599
600 void initPAM(void)
601 {
602     PyObject            *m, *d;
603
604     m = Py_InitModule("PAM", PyPAM_Methods);
605     d = PyModule_GetDict(m);
606     
607     PyPAM_Error = PyErr_NewException("PAM.error", NULL, NULL);
608     if (PyPAM_Error == NULL)
609         return;
610     PyDict_SetItemString(d, "error", PyPAM_Error);
611
612     PyPAMObject_Type.ob_type = &PyType_Type;
613     PyPAMObject_Type.tp_doc = PyPAMObject_doc;
614     Py_INCREF(&PyPAMObject_Type);
615
616     insint(d, "PAM_SUCCESS", PAM_SUCCESS);
617     insint(d, "PAM_OPEN_ERR", PAM_OPEN_ERR);
618     insint(d, "PAM_SYMBOL_ERR", PAM_SYMBOL_ERR);
619     insint(d, "PAM_SERVICE_ERR", PAM_SERVICE_ERR);
620     insint(d, "PAM_SYSTEM_ERR", PAM_SYSTEM_ERR);
621     insint(d, "PAM_BUF_ERR", PAM_BUF_ERR);
622     insint(d, "PAM_PERM_DENIED", PAM_PERM_DENIED);
623     insint(d, "PAM_AUTH_ERR", PAM_AUTH_ERR);
624     insint(d, "PAM_CRED_INSUFFICIENT", PAM_CRED_INSUFFICIENT);
625     insint(d, "PAM_AUTHINFO_UNAVAIL", PAM_AUTHINFO_UNAVAIL);
626     insint(d, "PAM_USER_UNKNOWN", PAM_USER_UNKNOWN);
627     insint(d, "PAM_MAXTRIES", PAM_MAXTRIES);
628     insint(d, "PAM_NEW_AUTHTOK_REQD", PAM_NEW_AUTHTOK_REQD);
629     insint(d, "PAM_ACCT_EXPIRED", PAM_ACCT_EXPIRED);
630     insint(d, "PAM_SESSION_ERR", PAM_SESSION_ERR);
631     insint(d, "PAM_CRED_UNAVAIL", PAM_CRED_UNAVAIL);
632     insint(d, "PAM_CRED_EXPIRED", PAM_CRED_EXPIRED);
633     insint(d, "PAM_CRED_ERR", PAM_CRED_ERR);
634     insint(d, "PAM_NO_MODULE_DATA", PAM_NO_MODULE_DATA);
635     insint(d, "PAM_CONV_ERR", PAM_CONV_ERR);
636     insint(d, "PAM_AUTHTOK_ERR", PAM_AUTHTOK_ERR);
637     insint(d, "PAM_AUTHTOK_RECOVER_ERR", PAM_AUTHTOK_RECOVER_ERR);
638     insint(d, "PAM_AUTHTOK_LOCK_BUSY", PAM_AUTHTOK_LOCK_BUSY);
639     insint(d, "PAM_AUTHTOK_DISABLE_AGING", PAM_AUTHTOK_DISABLE_AGING);
640     insint(d, "PAM_TRY_AGAIN", PAM_TRY_AGAIN);
641     insint(d, "PAM_IGNORE", PAM_IGNORE);
642     insint(d, "PAM_ABORT", PAM_ABORT);
643     insint(d, "PAM_AUTHTOK_EXPIRED", PAM_AUTHTOK_EXPIRED);
644     insint(d, "PAM_MODULE_UNKNOWN", PAM_MODULE_UNKNOWN);
645     insint(d, "PAM_BAD_ITEM", PAM_BAD_ITEM);
646     insint(d, "_PAM_RETURN_VALUES", _PAM_RETURN_VALUES);
647
648     insint(d, "PAM_SILENT", PAM_SILENT);
649     insint(d, "PAM_DISALLOW_NULL_AUTHTOK", PAM_DISALLOW_NULL_AUTHTOK);
650     insint(d, "PAM_ESTABLISH_CRED", PAM_ESTABLISH_CRED);
651     insint(d, "PAM_DELETE_CRED", PAM_DELETE_CRED);
652     insint(d, "PAM_REINITIALIZE_CRED", PAM_REINITIALIZE_CRED);
653     insint(d, "PAM_REFRESH_CRED", PAM_REFRESH_CRED);
654     insint(d, "PAM_CHANGE_EXPIRED_AUTHTOK", PAM_CHANGE_EXPIRED_AUTHTOK);
655
656     insint(d, "PAM_SERVICE", PAM_SERVICE);
657     insint(d, "PAM_USER", PAM_USER);
658     insint(d, "PAM_TTY", PAM_TTY);
659     insint(d, "PAM_RHOST", PAM_RHOST);
660     insint(d, "PAM_CONV", PAM_CONV);
661     /* These next two are most likely not needed for client apps */
662     insint(d, "PAM_RUSER", PAM_RUSER);
663     insint(d, "PAM_USER_PROMPT", PAM_USER_PROMPT);
664
665     insint(d, "PAM_DATA_SILENT", PAM_DATA_SILENT);
666
667     insint(d, "PAM_PROMPT_ECHO_OFF", PAM_PROMPT_ECHO_OFF);
668     insint(d, "PAM_PROMPT_ECHO_ON", PAM_PROMPT_ECHO_ON);
669     insint(d, "PAM_ERROR_MSG", PAM_ERROR_MSG);
670     insint(d, "PAM_TEXT_INFO", PAM_TEXT_INFO);
671 #ifdef __LINUX__
672     insint(d, "PAM_RADIO_TYPE", PAM_RADIO_TYPE);
673     insint(d, "PAM_BINARY_MSG", PAM_BINARY_MSG);
674     insint(d, "PAM_BINARY_PROMPT", PAM_BINARY_PROMPT);
675 #endif
676
677 }