aboutsummaryrefslogtreecommitdiff
path: root/ident/pam.c
diff options
context:
space:
mode:
Diffstat (limited to 'ident/pam.c')
-rw-r--r--ident/pam.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/ident/pam.c b/ident/pam.c
new file mode 100644
index 0000000..ef32c4d
--- /dev/null
+++ b/ident/pam.c
@@ -0,0 +1,230 @@
1/* This file is part of GNU Pies.
2 Copyright (C) 2015 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "ident.h"
18#include <grp.h>
19#include <security/pam_appl.h>
20
21struct pam_identity_provider_data
22{
23 char *service;
24};
25
26struct pam_cred
27{
28 const char *user;
29 const char *pass;
30};
31
32#define COPY_STRING(s) (s) ? strdup(s) : NULL
33
34#define overwrite_and_free(ptr) \
35 do { \
36 char *s = ptr; \
37 while (*s) \
38 *s++ = 0; \
39 } while (0)
40
41#ifndef PAM_AUTHTOK_RECOVER_ERR
42# define PAM_AUTHTOK_RECOVER_ERR PAM_CONV_ERR
43#endif
44
45static int
46pies_conv (int num_msg, const struct pam_message **msg,
47 struct pam_response **resp, void *appdata_ptr)
48{
49 int status = PAM_SUCCESS;
50 int i;
51 struct pam_response *reply = NULL;
52 struct pam_cred *cred = appdata_ptr;
53
54 reply = calloc (num_msg, sizeof (*reply));
55 if (!reply)
56 return PAM_CONV_ERR;
57
58 for (i = 0; i < num_msg && status == PAM_SUCCESS; i++)
59 {
60 switch (msg[i]->msg_style)
61 {
62 case PAM_PROMPT_ECHO_ON:
63 reply[i].resp_retcode = PAM_SUCCESS;
64 reply[i].resp = COPY_STRING (cred->user);
65 /* PAM frees resp */
66 break;
67
68 case PAM_PROMPT_ECHO_OFF:
69 if (cred->pass)
70 {
71 reply[i].resp_retcode = PAM_SUCCESS;
72 reply[i].resp = COPY_STRING (cred->pass);
73 /* PAM frees resp */
74 } else
75 status = PAM_AUTHTOK_RECOVER_ERR;
76 break;
77
78 case PAM_TEXT_INFO:
79 case PAM_ERROR_MSG:
80 reply[i].resp_retcode = PAM_SUCCESS;
81 reply[i].resp = NULL;
82 break;
83
84 default:
85 status = PAM_CONV_ERR;
86 }
87 }
88
89 if (status != PAM_SUCCESS)
90 {
91 for (i = 0; i < num_msg; i++)
92 if (reply[i].resp)
93 {
94 switch (msg[i]->msg_style)
95 {
96 case PAM_PROMPT_ECHO_ON:
97 case PAM_PROMPT_ECHO_OFF:
98 overwrite_and_free (reply[i].resp);
99 break;
100
101 case PAM_ERROR_MSG:
102 case PAM_TEXT_INFO:
103 free (reply[i].resp);
104 }
105 }
106 free (reply);
107 } else
108 *resp = reply;
109 return status;
110}
111
112static int
113authenticate (pies_identity_provider_t provider,
114 pies_identity_t id, char const *passwd)
115{
116 struct pam_identity_provider_data *pamdata = provider->data;
117 pam_handle_t *pamh;
118 int pamerror;
119 struct pam_cred cred = { id->username, passwd };
120 struct pam_conv pam_conv = { &pies_conv, &cred };
121 char const *service = pamdata->service ? pamdata->service : "pies";
122
123 do
124 {
125 pamerror = pam_start (service, id->username, &pam_conv, &pamh);
126 if (pamerror != PAM_SUCCESS)
127 break;
128
129 pamerror = pam_authenticate (pamh, 0);
130 if (pamerror != PAM_SUCCESS)
131 break;
132
133 pamerror = pam_acct_mgmt (pamh, 0);
134 if (pamerror != PAM_SUCCESS)
135 break;
136
137 pamerror = pam_setcred (pamh, PAM_ESTABLISH_CRED);
138 }
139 while (0);
140
141 pam_end (pamh, PAM_SUCCESS);
142
143 switch (pamerror)
144 {
145 case PAM_SUCCESS:
146 return 0;
147
148 case PAM_AUTH_ERR:
149 return -1;
150 }
151
152 //FIXME _log(L_ERR, 0, "PAM authentication error");
153 return -1;
154}
155
156static int
157is_group_member (pies_identity_provider_t p,
158 pies_identity_t id, char * const * groups)
159{
160 struct group *gr;
161 int result = 0;
162
163 setgrent ();
164 while ((gr = getgrent ()))
165 {
166 char **p;
167
168 if (!is_array_member (groups, gr->gr_name))
169 continue;
170
171 for (p = gr->gr_mem; *p; p++)
172 if (strcmp (*p, id->username) == 0)
173 {
174 result = 1;
175 break;
176 }
177 }
178 endgrent ();
179 return result;
180}
181
182static struct grecs_keyword pam_kw[] = {
183 { "type", "'pam", "Set mechanism type", grecs_type_null },
184 { "service", NULL, "Service name",
185 grecs_type_string, GRECS_DFLT, NULL,
186 offsetof(struct pam_identity_provider_data, service) },
187 { NULL }
188};
189
190static int
191configure (struct grecs_node *node, pies_identity_provider_t provider)
192{
193 int i;
194 struct pam_identity_provider_data *data = xcalloc (1, sizeof (*data));
195 provider->data = data;
196 for (i = 0; pam_kw[i].ident; i++)
197 pam_kw[i].varptr = data;
198 if (grecs_tree_process (node->down, pam_kw))
199 {
200 //FIXME: memory leak
201 return -1;
202 }
203 provider->locus = node->locus;
204 return 0;
205}
206
207static void
208confhelp (void)
209{
210 static struct grecs_keyword top[] = {
211 { "identity-provider", "name: string",
212 "Configuration for system identity provider",
213 grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL,
214 pam_kw },
215 { NULL }
216 };
217 grecs_print_statement_array (top, 1, 0, stdout);
218}
219
220struct pies_identity_mechanism pam_identity_mechanism = {
221 "pam",
222 authenticate,
223 is_group_member,
224 NULL,
225 configure,
226 confhelp
227};
228
229
230

Return to:

Send suggestions and report system problems to the System administrator.