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