965d4dca8bfd5ed74b52154da7c3d8dbccdb4bb7
[freeradius.git] / src / modules / rlm_unix / compat.c
1 /*
2  * compat.c     Compatibity routines for fgetpwent(), fgetspent(), and fgetgrent()
3  *
4  *              The code in here was borrowed from the cache.c module
5  *              and adapted to be a standalone set of functions.
6  *
7  * Version: $Id$
8  *
9  *   This program is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU General Public License as published by
11  *   the Free Software Foundation; either version 2 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This program is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with this program; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * Copyright 2001  The FreeRADIUS server project.
24  */    
25 static const char rcsid[] = "$Id$";
26
27 #include        "autoconf.h"
28 #include        "libradius.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <grp.h>
33 #include <pwd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include "config.h"
38
39 #ifdef HAVE_SHADOW_H
40 #  include <shadow.h>
41 #endif
42
43 #include "radiusd.h"
44 #include "cache.h"
45 #include "compat.h"
46
47
48 #ifndef HAVE_FGETPWENT
49
50 struct passwd *rad_fgetpwent(FILE *pwhandle) {
51         static struct passwd pwbuf;
52         static char username[MAX_STRING_LEN];
53         static char userpwd[64];
54         static char gecostmp[128];
55         static char homedirtmp[128];
56         static char shelltmp[128];
57         char uidtmp[16];
58         char gidtmp[16];
59         char *ptr, *bufptr;
60         char buffer[BUFSIZE];
61         int len;
62
63
64
65 #define RAD_EXTRACT_FIELD(txt_field, tmp_buf) \
66         for(bufptr = ptr; (*ptr != '\0') && (*ptr != '\n') && (*ptr != ':'); ptr++); \
67         len = ptr - bufptr; \
68         if((len+1) > sizeof(tmp_buf)) { \
69                 radlog(L_ERR, "rlm_unix:  %s too long in line: %s", (txt_field), buffer); \
70                 return rad_fgetpwent(pwhandle); \
71         } \
72         strncpy((tmp_buf), bufptr, len); \
73         (tmp_buf)[len] = '\0';
74
75
76
77         if (pwhandle == NULL)
78                 return NULL;
79
80         if (fgets(buffer, BUFSIZE , pwhandle) == (char *)NULL)
81                 return NULL;
82
83         memset(&pwbuf, 0, sizeof(struct passwd));
84         memset(username, 0, sizeof(username));
85         memset(userpwd, 0, sizeof(userpwd));
86         memset(gecostmp, 0, sizeof(gecostmp));
87         memset(homedirtmp, 0, sizeof(homedirtmp));
88         memset(shelltmp, 0, sizeof(shelltmp));
89         buffer[BUFSIZE] ='\0';
90
91         /* Get usernames from the password file */
92         ptr = buffer;
93         RAD_EXTRACT_FIELD("Username", username);
94         pwbuf.pw_name = username;
95         
96         /* Get (encrypted) password from password file (shadow comes later) */
97         if (*ptr != '\0') ptr++;
98         RAD_EXTRACT_FIELD("Password", userpwd);
99         pwbuf.pw_passwd = userpwd;
100
101         /* Get uid from the password file */
102         if (*ptr != '\0') ptr++;
103         RAD_EXTRACT_FIELD("UID", uidtmp);
104         pwbuf.pw_uid = atoi(uidtmp);
105         
106         /* Get gid from the password file */
107         if (*ptr != '\0') ptr++;
108         RAD_EXTRACT_FIELD("GID", gidtmp);
109         pwbuf.pw_gid = atoi(gidtmp);
110         
111         /* Get the GECOS (name) field from the password file */
112         if (*ptr != '\0') ptr++;
113         RAD_EXTRACT_FIELD("GECOS", gecostmp);
114         pwbuf.pw_gecos = gecostmp;
115
116         /* Get the home directory from the password file */
117         if (*ptr != '\0') ptr++;
118         RAD_EXTRACT_FIELD("Home dir", homedirtmp);
119         pwbuf.pw_dir = homedirtmp;
120
121         /* Get the shell from the password file */
122         if (*ptr != '\0') ptr++;
123         RAD_EXTRACT_FIELD("Shell", shelltmp);
124         pwbuf.pw_shell = shelltmp;
125
126         return(&pwbuf);
127 }
128
129 #undef RAD_EXTRACT_FIELD
130
131 #endif /* HAVE_FGETPWENT */
132
133
134
135
136 #ifndef HAVE_FGETSPENT
137
138 shadow_pwd_t *rad_fgetspent(FILE *sphandle) {
139         static shadow_pwd_t spbuf;
140         static char username[MAX_STRING_LEN];
141         static char userpwd[64];
142         char lastchgtmp[16];
143         char mintmp[16];
144         char maxtmp[16];
145         char warntmp[16];
146         char inactmp[16];
147         char expiretmp[16];
148         char *ptr, *bufptr;
149         char buffer[BUFSIZE];
150         int len;
151
152 #define RAD_EXTRACT_FIELD(txt_field, tmp_buf) \
153         for(bufptr = ptr; (*ptr != '\0') && (*ptr != '\n') && (*ptr != ':'); ptr++); \
154         len = ptr - bufptr; \
155         if((len+1) > sizeof(tmp_buf)) { \
156                 radlog(L_ERR, "rlm_unix:  %s too long in line: %s", (txt_field), buffer); \
157                 return rad_fgetspent(sphandle); \
158         } \
159         strncpy((tmp_buf), bufptr, len); \
160         (tmp_buf)[len] = '\0';
161
162
163
164         if (sphandle == NULL)
165                 return NULL;
166
167         if (fgets(buffer, BUFSIZE, sphandle) == (char *)NULL)
168                 return NULL;
169
170         memset(&spbuf, 0, sizeof(shadow_pwd_t));
171         memset(username, 0, sizeof(username));
172         memset(userpwd, 0, sizeof(userpwd));
173         buffer[BUFSIZE] ='\0';
174
175         /* Get usernames from the shadow file */
176         ptr = buffer;
177         RAD_EXTRACT_FIELD("Username", username);
178         GET_SP_NAME(&spbuf) = username;
179         
180         /* Get (encrypted) passwords from the shadow file */
181         if (*ptr != '\0') ptr++;
182         RAD_EXTRACT_FIELD("Password", userpwd);
183         GET_SP_PWD(&spbuf) = userpwd;
184
185         /* Get the 'last change' field from the shadow file */
186 #ifdef GET_SP_LSTCHG
187         if (*ptr != '\0') ptr++;
188         RAD_EXTRACT_FIELD("'Last change'", lastchgtmp);
189         GET_SP_LSTCHG(&spbuf) = atoi(lastchgtmp);
190 #endif
191
192         /* Get the 'minimum time between changes' field from the shadow file */
193 #ifdef GET_SP_MIN
194         if (*ptr != '\0') ptr++;
195         RAD_EXTRACT_FIELD("'Min change'", mintmp);
196         GET_SP_MIN(&spbuf) = atoi(mintmp);
197 #endif
198
199         /* Get the 'maximum time between changes' field from the shadow file */
200 #ifdef GET_SP_MAX
201         if (*ptr != '\0') ptr++;
202         RAD_EXTRACT_FIELD("'Max change'", maxtmp);
203         GET_SP_MAX(&spbuf) = atoi(maxtmp);
204 #endif
205
206         /* Get the 'expire warning time' field from the shadow file */
207 #ifdef GET_SP_WARN
208         if (*ptr != '\0') ptr++;
209         RAD_EXTRACT_FIELD("'Warn time'", warntmp);
210         GET_SP_WARN(&spbuf) = atoi(warntmp);
211 #endif
212
213         /* Get the 'account inactivity time' field from the shadow file */
214 #ifdef GET_SP_INACT
215         if (*ptr != '\0') ptr++;
216         RAD_EXTRACT_FIELD("'Inactive time'", inactmp);
217         GET_SP_INACT(&spbuf) = atoi(inactmp);
218 #endif
219
220         /* Get the 'expire time' field from the shadow file */
221 #ifdef GET_SP_EXPIRE
222         if (*ptr != '\0') ptr++;
223         RAD_EXTRACT_FIELD("'Expire time'", expiretmp);
224         GET_SP_EXPIRE(&spbuf) = atoi(expiretmp);
225 #endif
226         return (&spbuf);
227 }
228
229 #undef RAD_EXTRACT_FIELD
230
231 #endif  /* HAVE_FGETSPENT */
232
233
234
235 #ifndef HAVE_FGETGRENT
236
237 #define RAD_MAX_GROUP_MEMBERS 500
238
239 struct group *rad_fgetgrent(FILE *grhandle) {
240         static struct group grbuf;
241         static char grname[MAX_STRING_LEN];
242         static char grpwd[64];
243         static char *grmem[RAD_MAX_GROUP_MEMBERS];
244         static char grmembuf[2048];
245         char gidtmp[16];
246         char *ptr, *bufptr, *grptr;
247         char buffer[BUFSIZE];
248         int len, gidx;
249
250
251
252 #define RAD_EXTRACT_FIELD(txt_field, tmp_buf) \
253         for(bufptr = ptr; (*ptr != '\0') && (*ptr != '\n') && (*ptr != ':'); ptr++); \
254         len = ptr - bufptr; \
255         if((len+1) > sizeof(tmp_buf)) { \
256                 radlog(L_ERR, "rlm_unix:  %s too long in line: %s", (txt_field), buffer); \
257                 return rad_fgetgrent(grhandle); \
258         } \
259         strncpy((tmp_buf), bufptr, len); \
260         (tmp_buf)[len] = '\0';
261
262
263
264         if (grhandle == NULL)
265                 return NULL;
266
267         if (fgets(buffer, BUFSIZE, grhandle) == (char *)NULL)
268                 return NULL;
269
270         memset(&grbuf, 0, sizeof(struct group));
271         memset(grname, 0, sizeof(grname));
272         memset(grpwd, 0, sizeof(grpwd));
273         memset(grmem, 0, sizeof(grmem));
274         memset(grmembuf, 0, sizeof(grmembuf));
275         buffer[BUFSIZE] ='\0';
276
277         /* Get the group name */
278         ptr = buffer;
279         RAD_EXTRACT_FIELD("Group name", grname);
280         grbuf.gr_name = grname;
281
282         /* Get the group password */
283         if (*ptr != '\0') ptr++;
284         RAD_EXTRACT_FIELD("Group password", grpwd);
285         grbuf.gr_passwd = grpwd;
286
287         /* Get the group id */
288         if (*ptr != '\0') ptr++;
289         RAD_EXTRACT_FIELD("Group ID", gidtmp);
290         grbuf.gr_gid = atoi(gidtmp);
291
292         /* Collect all of the group members... */
293         gidx = 0;
294         grbuf.gr_mem = grmem;
295         grbuf.gr_mem[gidx] = NULL;
296         grptr = grmembuf;
297         while (*ptr != '\0') {
298                 if (*ptr != '\0') ptr++;
299                 for(bufptr = ptr; (*ptr != '\0') && (*ptr != '\n') && (*ptr != ','); ptr++);
300                 len = ptr - bufptr;
301
302                 /* Ignore "NULL" entries... */
303                 if (len == 0) continue;
304
305                 if((len+1) > (sizeof(grmembuf) - (grptr - grmembuf))) {
306                         radlog(L_ERR, "rlm_unix:  Some entries dropped.  Group members line too long: %s", buffer);
307                         /* Return a partial list */
308                         return (&grbuf);
309                 }
310
311                 /* Prevent buffer overflows! */
312                 if (gidx+1 >= RAD_MAX_GROUP_MEMBERS) {
313                         radlog(L_ERR, "rlm_unix:  Some entries dropped.  Too many group members: %s", buffer);
314                         /* Return a partial list */
315                         return (&grbuf);
316                 }
317
318                 strncpy(grptr, bufptr, len);
319                 grptr[len] = '\0';
320                 grbuf.gr_mem[gidx++] = grptr;
321                 grbuf.gr_mem[gidx] = NULL;
322                 grptr += len + 1;
323
324         }
325         return (&grbuf);
326 }
327
328 #undef RAD_EXTRACT_FIELD
329
330 #endif /* HAVE_FGETGRENT */