1 /*
2 Pam module to change user names arbitrarily in the pam stack.
3
4 Compile as
5
6 gcc pam_user_map.c -shared -lpam -fPIC -o pam_user_map.so
7
8 Install as appropriate (for example, in /lib/security/).
9 Add to your /etc/pam.d/mysql (preferably, at the end) this line:
10 =========================================================
11 auth required pam_user_map.so
12 =========================================================
13
14 And create /etc/security/user_map.conf with the desired mapping
15 in the format: orig_user_name: mapped_user_name
16 @user's_group_name: mapped_user_name
17 =========================================================
18 #comments and empty lines are ignored
19 john: jack
20 bob: admin
21 top: accounting
22 @group_ro: readonly
23 =========================================================
24
25 If something doesn't work as expected you can get verbose
26 comments with the 'debug' option like this
27 =========================================================
28 auth required pam_user_map.so debug
29 =========================================================
30 These comments are written to the syslog as 'authpriv.debug'
31 and usually end up in /var/log/secure file.
32 */
33
34 #include <config_auth_pam.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <grp.h>
41 #include <pwd.h>
42
43 #ifdef HAVE_PAM_EXT_H
44 #include <security/pam_ext.h>
45 #endif
46
47 #ifdef HAVE_PAM_APPL_H
48 #include <unistd.h>
49 #include <security/pam_appl.h>
50 #endif
51
52 #include <security/pam_modules.h>
53
54 #ifndef HAVE_PAM_SYSLOG
55 #include <stdarg.h>
56 static void
pam_syslog(const pam_handle_t * pamh,int priority,const char * fmt,...)57 pam_syslog (const pam_handle_t *pamh, int priority,
58 const char *fmt, ...)
59 {
60 va_list args;
61 va_start (args, fmt);
62 vsyslog (priority, fmt, args);
63 va_end (args);
64 }
65 #endif
66
67 #define FILENAME "/etc/security/user_map.conf"
68 #define skip(what) while (*s && (what)) s++
69 #define SYSLOG_DEBUG if (mode_debug) pam_syslog
70
71 #define GROUP_BUFFER_SIZE 100
72 static const char debug_keyword[]= "debug";
73
74 #ifdef HAVE_POSIX_GETGROUPLIST
75 typedef gid_t my_gid_t;
76 #else
77 typedef int my_gid_t;
78 #endif
79
populate_user_groups(const char * user,my_gid_t ** groups)80 static int populate_user_groups(const char *user, my_gid_t **groups)
81 {
82 my_gid_t user_group_id;
83 my_gid_t *loc_groups= *groups;
84 int ng;
85
86 {
87 struct passwd *pw= getpwnam(user);
88 if (!pw)
89 return 0;
90 user_group_id= pw->pw_gid;
91 }
92
93 ng= GROUP_BUFFER_SIZE;
94 if (getgrouplist(user, user_group_id, loc_groups, &ng) < 0)
95 {
96 /* The rare case when the user is present in more than */
97 /* GROUP_BUFFER_SIZE groups. */
98 loc_groups= (my_gid_t *) malloc(ng * sizeof (my_gid_t));
99
100 if (!loc_groups)
101 return 0;
102
103 (void) getgrouplist(user, user_group_id, loc_groups, &ng);
104 *groups= (my_gid_t*)loc_groups;
105 }
106
107 return ng;
108 }
109
110
user_in_group(const my_gid_t * user_groups,int ng,const char * group)111 static int user_in_group(const my_gid_t *user_groups, int ng,const char *group)
112 {
113 my_gid_t group_id;
114 const my_gid_t *groups_end = user_groups + ng;
115
116 {
117 struct group *g= getgrnam(group);
118 if (!g)
119 return 0;
120 group_id= g->gr_gid;
121 }
122
123 for (; user_groups < groups_end; user_groups++)
124 {
125 if (*user_groups == group_id)
126 return 1;
127 }
128
129 return 0;
130 }
131
132
print_groups(pam_handle_t * pamh,const my_gid_t * user_groups,int ng)133 static void print_groups(pam_handle_t *pamh, const my_gid_t *user_groups, int ng)
134 {
135 char buf[256];
136 char *c_buf= buf, *buf_end= buf+sizeof(buf)-2;
137 struct group *gr;
138 int cg;
139
140 for (cg=0; cg < ng; cg++)
141 {
142 char *c;
143 if (c_buf == buf_end)
144 break;
145 *(c_buf++)= ',';
146 if (!(gr= getgrgid(user_groups[cg])) ||
147 !(c= gr->gr_name))
148 continue;
149 while (*c)
150 {
151 if (c_buf == buf_end)
152 break;
153 *(c_buf++)= *(c++);
154 }
155 }
156 c_buf[0]= c_buf[1]= 0;
157 pam_syslog(pamh, LOG_DEBUG, "User belongs to %d %s [%s].\n",
158 ng, (ng == 1) ? "group" : "groups", buf+1);
159 }
160
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char * argv[])161 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
162 int argc, const char *argv[])
163 {
164 int mode_debug= 0;
165 int pam_err, line= 0;
166 const char *username;
167 char buf[256];
168 FILE *f;
169 my_gid_t group_buffer[GROUP_BUFFER_SIZE];
170 my_gid_t *groups= group_buffer;
171 int n_groups= -1;
172
173 for (; argc > 0; argc--)
174 {
175 if (strcasecmp(argv[argc-1], debug_keyword) == 0)
176 mode_debug= 1;
177 }
178
179 SYSLOG_DEBUG(pamh, LOG_DEBUG, "Opening file '%s'.\n", FILENAME);
180
181 f= fopen(FILENAME, "r");
182 if (f == NULL)
183 {
184 pam_syslog(pamh, LOG_ERR, "Cannot open '%s'\n", FILENAME);
185 return PAM_SYSTEM_ERR;
186 }
187
188 pam_err = pam_get_item(pamh, PAM_USER, (const void**)&username);
189 if (pam_err != PAM_SUCCESS)
190 {
191 pam_syslog(pamh, LOG_ERR, "Cannot get username.\n");
192 goto ret;
193 }
194
195 SYSLOG_DEBUG(pamh, LOG_DEBUG, "Incoming username '%s'.\n", username);
196
197 while (fgets(buf, sizeof(buf), f) != NULL)
198 {
199 char *s= buf, *from, *to, *end_from, *end_to;
200 int check_group;
201 int cmp_result;
202
203 line++;
204
205 skip(isspace(*s));
206 if (*s == '#' || *s == 0) continue;
207 if ((check_group= *s == '@'))
208 {
209 if (n_groups < 0)
210 {
211 n_groups= populate_user_groups(username, &groups);
212 if (mode_debug)
213 print_groups(pamh, groups, n_groups);
214 }
215 s++;
216 }
217 from= s;
218 skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
219 (*s == '$') || (*s == '\\') || (*s == '/'));
220 end_from= s;
221 skip(isspace(*s));
222 if (end_from == from || *s++ != ':') goto syntax_error;
223 skip(isspace(*s));
224 to= s;
225 skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
226 (*s == '$'));
227 end_to= s;
228 if (end_to == to) goto syntax_error;
229
230 *end_from= *end_to= 0;
231
232 if (check_group)
233 {
234 cmp_result= user_in_group(groups, n_groups, from);
235 SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if user is in group '%s': %s\n",
236 from, cmp_result ? "YES":"NO");
237 }
238 else
239 {
240 cmp_result= (strcmp(username, from) == 0);
241 SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if username '%s': %s\n",
242 from, cmp_result ? "YES":"NO");
243 }
244 if (cmp_result)
245 {
246 pam_err= pam_set_item(pamh, PAM_USER, to);
247 SYSLOG_DEBUG(pamh, LOG_DEBUG,
248 (pam_err == PAM_SUCCESS) ? "User mapped as '%s'\n" :
249 "Couldn't map as '%s'\n", to);
250 goto ret;
251 }
252 }
253
254 SYSLOG_DEBUG(pamh, LOG_DEBUG, "User not found in the list.\n");
255 pam_err= PAM_AUTH_ERR;
256 goto ret;
257
258 syntax_error:
259 pam_syslog(pamh, LOG_ERR, "Syntax error at %s:%d", FILENAME, line);
260 pam_err= PAM_SYSTEM_ERR;
261 ret:
262 if (groups != group_buffer)
263 free(groups);
264
265 fclose(f);
266
267 return pam_err;
268 }
269
270
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char * argv[])271 int pam_sm_setcred(pam_handle_t *pamh, int flags,
272 int argc, const char *argv[])
273 {
274
275 return PAM_SUCCESS;
276 }
277
278