Imported upstream version 0.59.3
[hcoop/debian/courier-authlib.git] / userdb / userdb.c
1 /*
2 ** Copyright 1998 - 2007 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5
6 #if HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9 #include "dbobj.h"
10 #include "userdb.h"
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <time.h>
16 #include <sys/types.h>
17 #if HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20
21 static const char rcsid[]="$Id: userdb.c,v 1.10 2007/04/14 03:02:46 mrsam Exp $";
22
23 static struct dbobj d;
24 static time_t dt;
25 static ino_t di;
26
27 static int initialized=0;
28 int userdb_debug_level=0;
29
30 /* Open userdb.dat, if already opened, see if it changed, if so reopen */
31
32 void userdb_init(const char *n)
33 {
34 struct stat stat_buf;
35
36 if (initialized)
37 {
38 if (stat(n, &stat_buf) ||
39 stat_buf.st_mtime != dt ||
40 stat_buf.st_ino != di)
41 {
42 dbobj_close(&d);
43 initialized=0;
44 dt=stat_buf.st_mtime;
45 di=stat_buf.st_ino;
46 }
47 }
48 else if (stat(n, &stat_buf))
49 {
50 if (userdb_debug_level)
51 fprintf(stderr,
52 "DEBUG: userdb: unable to stat %s: %s\n",
53 n, strerror(errno));
54 return;
55 }
56 else
57 {
58 dt=stat_buf.st_mtime;
59 di=stat_buf.st_ino;
60 }
61
62 if (!initialized)
63 {
64 if (dbobj_open(&d, n, "R"))
65 {
66 if (userdb_debug_level)
67 fprintf(stderr,
68 "DEBUG: userdb: failed to open %s\n",
69 n);
70 return;
71 }
72 if (userdb_debug_level)
73 fprintf(stderr, "DEBUG: userdb: opened %s\n", n);
74 initialized=1;
75 }
76 }
77
78 void userdb_close()
79 {
80 if (initialized)
81 {
82 dbobj_close(&d);
83 initialized=0;
84 }
85 userdb_debug_level=0;
86 }
87
88 void userdb_set_debug(int lvl)
89 {
90 userdb_debug_level = lvl;
91 }
92
93 /* Fetch a record from userdb.dat */
94
95 char *userdb(const char *u)
96 {
97 char *p,*q;
98 size_t l;
99
100 if (!initialized)
101 {
102 errno=ENOENT;
103 return (0);
104 }
105
106 q=dbobj_fetch(&d, u, strlen(u), &l, "");
107 if (!q)
108 {
109 if (userdb_debug_level)
110 fprintf(stderr, "DEBUG: userdb: entry not found\n");
111 errno=ENOENT;
112 return(0);
113 }
114
115 p=malloc(l+1);
116 if (!p)
117 {
118 free(q);
119 return (0);
120 }
121
122 if (l) memcpy(p, q, l);
123 free(q);
124 p[l]=0;
125 return (p);
126 }
127
128 /* Return a pointer to a specific field in this record */
129
130 const char *userdb_get(const char *u, const char *n, int *l)
131 {
132 int nl=strlen(n);
133
134 while (u && *u)
135 {
136 if (memcmp(u, n, nl) == 0 &&
137 (u[nl] == 0 || u[nl] == '=' || u[nl] == '|'))
138 {
139 u += nl;
140 *l=0;
141 if (*u == '=')
142 {
143 ++u;
144 while ( u[*l] && u[*l] != '|')
145 ++ *l;
146 }
147 return (u);
148 }
149 u=strchr(u, '|');
150 if (u) ++u;
151 }
152 return (0);
153 }
154
155 /* Extract field as an unsigned int */
156
157 unsigned userdb_getu(const char *u, const char *n, unsigned defnum)
158 {
159 int l;
160 const char *p;
161
162 if ((p=userdb_get(u, n, &l)) != 0)
163 {
164 defnum=0;
165 while (l && *p >= '0' && *p <= '9')
166 {
167 defnum = defnum * 10 + (*p++ - '0');
168 --l;
169 }
170 }
171 return (defnum);
172 }
173
174 /* Extract a field into a dynamically allocated buffer */
175
176 char *userdb_gets(const char *u, const char *n)
177 {
178 int l;
179 const char *p;
180 char *q;
181
182 if ((p=userdb_get(u, n, &l)) != 0)
183 {
184 q=malloc(l+1);
185 if (!q)
186 return (0);
187
188 if (l) memcpy(q, p, l);
189 q[l]=0;
190 return (q);
191 }
192 errno=ENOENT;
193 return (0);
194 }
195
196 /* Create a userdbs structure based upon a uid (reverse lookup) */
197
198 struct userdbs *userdb_createsuid(uid_t u)
199 {
200 char buf[80];
201 char *p=buf+sizeof(buf)-1, *q;
202 struct userdbs *s;
203
204 /* Lookup uid= record */
205
206 *p=0;
207 *--p='=';
208 do
209 {
210 *--p= "0123456789"[u % 10];
211 u=u/10;
212 } while (u);
213 p=userdb(p);
214 if (!p) return (0);
215
216 /* Have account name, now look it up. */
217
218 q=userdb(p);
219 if (!q)
220 {
221 free(p);
222 return (0);
223 }
224 s=userdb_creates(q);
225 if (s)
226 s->udb_name=p;
227 else
228 free(p);
229 free(q);
230 return (s);
231 }
232
233 static struct userdbs *userdb_enum(char *key, size_t keylen,
234 char *val, size_t vallen)
235 {
236 if (key)
237 {
238 char *valz=malloc(vallen+1);
239
240 if (valz)
241 {
242 struct userdbs *udbs;
243
244 memcpy(valz, val, vallen);
245 valz[vallen]=0;
246
247 udbs=userdb_creates(valz);
248
249 if (udbs)
250 {
251 if ((udbs->udb_name=malloc(keylen+1)) != NULL)
252 {
253 memcpy(udbs->udb_name, key, keylen);
254 udbs->udb_name[keylen]=0;
255 free(valz);
256 return udbs;
257 }
258 userdb_frees(udbs);
259 }
260 free(valz);
261 }
262 }
263 return NULL;
264 }
265
266
267 struct userdbs *userdb_enum_first()
268 {
269 char *val;
270 size_t vallen;
271 size_t keylen;
272 char *key=dbobj_firstkey(&d, &keylen, &val, &vallen);
273
274 if (key)
275 {
276 struct userdbs *udbs=userdb_enum(key, keylen, val, vallen);
277
278 free(val);
279
280 if (udbs)
281 return udbs;
282
283 /* Could be a reverse UID entry */
284
285 return userdb_enum_next();
286 }
287 return NULL;
288 }
289
290 struct userdbs *userdb_enum_next()
291 {
292 char *val;
293 size_t vallen;
294 size_t keylen;
295 char *key;
296
297 while ((key=dbobj_nextkey(&d, &keylen, &val, &vallen)) != NULL)
298 {
299 struct userdbs *udbs=userdb_enum(key, keylen, val, vallen);
300
301 free(val);
302
303 if (udbs)
304 return udbs;
305 }
306 return NULL;
307 }
308
309 /* Extracted a userdb.dat record, convert it to a userdbs structure */
310
311 struct userdbs *userdb_creates(const char *u)
312 {
313 struct userdbs *udbs=(struct userdbs *)malloc(sizeof(struct userdbs));
314 char *s;
315
316 if (!udbs) return (0);
317 memset((char *)udbs, 0, sizeof(*udbs));
318
319 if ((udbs->udb_dir=userdb_gets(u, "home")) == 0)
320 {
321 if (userdb_debug_level)
322 fprintf(stderr,
323 "DEBUG: userdb: required value 'home' is missing\n");
324 userdb_frees(udbs);
325 return (0);
326 }
327
328 if ((s=userdb_gets(u, "uid")) != 0)
329 {
330 udbs->udb_uid=atol(s);
331 free(s);
332 if ((s=userdb_gets(u, "gid")) != 0)
333 {
334 udbs->udb_gid=atol(s);
335 free(s);
336
337 if ((s=userdb_gets(u, "shell")) != 0)
338 udbs->udb_shell=s;
339 else if (errno != ENOENT)
340 {
341 userdb_frees(udbs);
342 return (0);
343 }
344
345 if ((s=userdb_gets(u, "mail")) != 0)
346 udbs->udb_mailbox=s;
347 else if (errno != ENOENT)
348 {
349 userdb_frees(udbs);
350 return (0);
351 }
352 if ((s=userdb_gets(u, "quota")) != 0)
353 udbs->udb_quota=s;
354 else if (errno != ENOENT)
355 {
356 userdb_frees(udbs);
357 return (0);
358 }
359 if ((s=userdb_gets(u, "gecos")) != 0)
360 udbs->udb_gecos=s;
361 else if (errno != ENOENT)
362 {
363 userdb_frees(udbs);
364 return (0);
365 }
366 if ((s=userdb_gets(u, "options")) != 0)
367 udbs->udb_options=s;
368 else if (errno != ENOENT)
369 {
370 userdb_frees(udbs);
371 return (0);
372 }
373 udbs->udb_source=userdb_gets(u, "_");
374 if (userdb_debug_level)
375 fprintf(stderr,
376 "DEBUG: userdb: home=%s, uid=%ld, gid=%ld, shell=%s, "
377 "mail=%s, quota=%s, gecos=%s, options=%s\n",
378 udbs->udb_dir ? udbs->udb_dir : "<unset>",
379 (long)udbs->udb_uid, (long)udbs->udb_gid,
380 udbs->udb_shell ? udbs->udb_shell : "<unset>",
381 udbs->udb_mailbox ? udbs->udb_mailbox : "<unset>",
382 udbs->udb_quota ? udbs->udb_quota : "<unset>",
383 udbs->udb_gecos ? udbs->udb_gecos : "<unset>",
384 udbs->udb_options ? udbs->udb_options : "<unset>");
385 return (udbs);
386 }
387 else
388 if (userdb_debug_level)
389 fprintf(stderr,
390 "DEBUG: userdb: required value 'gid' is missing\n");
391 }
392 else
393 if (userdb_debug_level)
394 fprintf(stderr,
395 "DEBUG: userdb: required value 'uid' is missing\n");
396 userdb_frees(udbs);
397 return (0);
398 }
399
400 void userdb_frees(struct userdbs *u)
401 {
402 if (u->udb_options) free(u->udb_options);
403 if (u->udb_name) free(u->udb_name);
404 if (u->udb_gecos) free(u->udb_gecos);
405 if (u->udb_dir) free(u->udb_dir);
406 if (u->udb_shell) free(u->udb_shell);
407 if (u->udb_mailbox) free(u->udb_mailbox);
408 if (u->udb_quota) free(u->udb_quota);
409 if (u->udb_source) free(u->udb_source);
410 free(u);
411 }
412