libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / system / libroot / posix / pwd_query.c
blob1fe7f57a5320add40dfae0c453724e2fc0b97860
2 /*
3 * This is a reimplementation of the BeOS R5 query-based multi-user system.
4 * (c) 2005, François Revol.
5 * provided under the MIT licence
6 */
8 //#ifdef REAL_MULTIUSER
9 #if 1
11 #include <pwd.h>
12 #include <grp.h>
14 #include <errno.h>
15 #include <fs_attr.h>
16 #include <fs_info.h>
17 #include <fs_query.h>
18 #include <string.h>
19 #include <TLS.h>
20 #include <Debug.h>
21 #include <TypeConstants.h>
23 #include <errno_private.h>
26 * Some notes.
27 * Users are stored in an fs node (not necessarily a regular file,
28 * that could be a dir, even the user's home dir,
29 * though we should be careful as they are owned by users.
33 #define GR_MAX_NAME 32
35 #define PW_MAX_NAME 32
36 #define PW_MAX_DIR B_PATH_NAME_LENGTH
37 #define PW_MAX_GECOS 128
38 #define PW_MAX_PASSWD 32
39 #define PW_MAX_SHELL B_PATH_NAME_LENGTH
41 /* should be more than enough :) */
42 #define GRBUFFSZ (GR_MAX_NAME + 2)
43 #define PWBUFFSZ (PW_MAX_NAME + PW_MAX_DIR + PW_MAX_GECOS + PW_MAX_PASSWD + PW_MAX_SHELL + 4)
46 /* attribute names we use to store groups & users. */
47 /* pets nm & strings */
49 static const char *B_GR_GID = "sys:group:gid";
50 static const char *B_GR_NAME = "sys:group:name";
51 //static const char *B_GR_PASSWD = "sys:group:passwd";
53 static const char *B_PW_DIR = "sys:user:dir";
54 static const char *B_PW_GECOS = "sys:user:fullname";
55 static const char *B_PW_GID = "sys:user:gid";
56 static const char *B_PW_NAME = "sys:user:name";
57 static const char *B_PW_PASSWD = "sys:user:passwd";
58 static const char *B_PW_SHELL = "sys:user:shell";
59 static const char *B_PW_UID = "sys:user:uid";
61 /* queries */
62 static const char *Q_GR_ALL = "sys:group:gid>-1";
63 static const char *QT_GR_GID = "sys:group:gid==%d";
64 static const char *QT_GR_NAM = "sys:group:name==\"%s\"";
65 static const char *Q_PW_ALL = "sys:user:uid>-1";
66 static const char *QT_PW_UID = "sys:user:uid==%d";
67 static const char *QT_PW_NAM = "sys:user:name==\"%s\"";
69 extern void __init_pwd_stuff(void);
70 extern void __fini_pwd_stuff(void);
72 static char *default_gr_members[] = { /*"baron",*/ NULL };
74 static dev_t boot_device;
76 /* TLS stuff */
78 static int32 pw_tls_id;
80 typedef struct pw_tls {
81 DIR *grent_query;
82 DIR *pwent_query;
84 int gridx;
85 int pwidx;
87 char grfile[B_PATH_NAME_LENGTH+1]; /* current group's cached file path */
88 char pwfile[B_PATH_NAME_LENGTH+1]; /* current user's cached file path */
90 struct group grent;
91 char grbuff[GRBUFFSZ]; /* XXX: merge with pwbuff ? */
93 struct passwd pwent;
94 char pwbuff[PWBUFFSZ];
95 } pw_tls_t;
97 struct pw_tls *get_pw_tls(void)
99 pw_tls_t *p = (pw_tls_t *)tls_get(pw_tls_id);
100 PRINT(("%s()\n", __FUNCTION__));
102 if (!p) {
103 p = (pw_tls_t *)malloc(sizeof(pw_tls_t));
104 if (!p)
105 return NULL;
106 memset(p, 0, sizeof(pw_tls_t));
107 p->grent_query = NULL;
108 p->pwent_query = NULL;
109 tls_set(pw_tls_id, p);
111 return p;
114 /* fill the path from the dirent and open() */
115 int dentopen(struct dirent *dent, char *path)
117 int err;
118 PRINT(("%s({%ld, %Ld, %ld, %Ld, %s}, )\n", __FUNCTION__, dent->d_pdev, dent->d_pino, dent->d_dev, dent->d_ino, dent->d_name));
119 dent->d_dev = boot_device;
120 err = get_path_for_dirent(dent, path, B_PATH_NAME_LENGTH);
121 if ((err < 0) || (path[0] != '/')) {
122 __set_errno(err);
123 return -1;
125 PRINT(("%s: open(%s)\n", __FUNCTION__, path));
126 return open(path, O_RDONLY);
129 /* group stuff */
131 int fill_grent_default(struct group *gbuf)
133 PRINT(("%s()\n", __FUNCTION__));
134 gbuf->gr_gid = 1000;
135 gbuf->gr_name = gbuf->gr_gid?"users":"wheel";
136 gbuf->gr_passwd = "";
137 gbuf->gr_mem = default_gr_members;
138 return 0;
141 int fill_grent_from_fd(int fd, struct group *gbuf, char *buf, size_t buflen)
143 size_t left;
144 ssize_t len;
145 left = buflen;
146 len = fs_read_attr(fd, B_GR_GID, B_INT32_TYPE, 0LL, &gbuf->gr_gid, sizeof(gid_t));
147 if (len < 0)
148 return fill_grent_default(gbuf);
149 PRINT(("%s: got gid\n", __FUNCTION__));
150 gbuf->gr_passwd = "";
151 gbuf->gr_mem = default_gr_members;
153 if (left < GR_MAX_NAME + 1)
154 return ERANGE;
155 len = fs_read_attr(fd, B_GR_NAME, B_STRING_TYPE, 0LL, buf, GR_MAX_NAME);
156 if (len < 0)
157 return fill_grent_default(gbuf);
158 gbuf->gr_name = buf;
159 buf[len] = '\0';
160 left -= len + 1;
161 buf += len + 1;
162 PRINT(("%s: got name\n", __FUNCTION__));
163 return 0;
166 void setgrent(void)
168 pw_tls_t *p;
169 p = get_pw_tls();
170 PRINT(("%s()\n", __FUNCTION__));
171 if (p->grent_query) /* clumsy apps */
172 fs_close_query(p->grent_query);
173 p->grent_query = fs_open_query(boot_device, Q_GR_ALL, 0);
174 PRINT(("pwq: %p\n", p->grent_query));
175 p->gridx = 0;
178 void endgrent(void)
180 pw_tls_t *p;
181 PRINT(("%s()\n", __FUNCTION__));
182 p = get_pw_tls();
184 if (p->grent_query)
185 fs_close_query(p->grent_query);
186 p->grent_query = NULL;
187 p->gridx = -1;
191 /* this conforms to the linux getgrent_r (there are several protos for that one... crap) */
192 /* note the FILE * based version is not supported as it makes no sense here */
193 int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp)
195 pw_tls_t *p;
196 int err;
197 int fd;
198 struct dirent *dent;
199 PRINT(("%s()\n", __FUNCTION__));
200 p = get_pw_tls();
201 if (!p)
202 return ENOMEM;
203 PRINT(("getgrent_r: grq = %p, idx = %d\n", p->grent_query, p->gridx));
204 if (!p->grent_query)
205 setgrent(); /* y0u clumsy app! */
206 if (!p->grent_query)
207 return EIO; /* something happened... */
208 __set_errno(0);
209 dent = fs_read_query(p->grent_query);
210 *gbufp = NULL;
211 if (!dent) {
212 /* found nothing on first iteration ? */
213 if (p->gridx == 0) {
214 if (fill_grent_default(gbuf) < 0)
215 return -1;
216 *gbufp = gbuf;
217 p->gridx++;
219 return 0;
221 fd = dentopen(dent, p->grfile);
222 if (fd < B_OK)
223 return errno?errno:-1;
224 err = fill_grent_from_fd(fd, gbuf, buf, buflen);
225 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err));
226 close(fd);
227 if (err)
228 return err;
229 p->gridx++;
230 *gbufp = gbuf;
231 return 0;
234 struct group *getgrent(void)
236 pw_tls_t *p;
237 struct group *ent;
238 int err;
239 PRINT(("%s()\n", __FUNCTION__));
240 p = get_pw_tls();
241 if (!p) {
242 /* we are really bork */
243 __set_errno(ENOMEM);
244 return NULL;
246 err = getgrent_r(&p->grent, p->grbuff, GRBUFFSZ, &ent);
247 if (err < 0) {
248 __set_errno(err);
249 return NULL;
251 if (!ent)
252 return NULL;
253 PRINT(("getgrent(); returning entry for %s\n", ent->gr_name));
254 return ent;
257 /* by gid */
258 struct group *getgrgid(gid_t gid)
260 struct dirent *dent;
261 pw_tls_t *p;
262 DIR *query;
263 int err;
264 int fd;
266 PRINT(("%s()\n", __FUNCTION__));
267 p = get_pw_tls();
268 if (!p) {
269 /* we are really bork */
270 __set_errno(ENOMEM);
271 return NULL;
274 /* reusing path */
275 sprintf(p->grfile, QT_GR_GID, gid);
276 query = fs_open_query(boot_device, p->grfile, 0);
277 PRINT(("q: %p\n", query));
278 if (!query)
279 return NULL;
281 dent = fs_read_query(query);
282 if (!dent) {
283 fs_close_query(query);
284 return NULL;
286 fd = dentopen(dent, p->grfile);
287 fs_close_query(query);
288 if (fd < B_OK)
289 return NULL;
290 err = fill_grent_from_fd(fd, &p->grent, p->grbuff, GRBUFFSZ);
291 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err));
292 close(fd);
293 if (err)
294 return NULL;
295 return &p->grent;
299 /* by name */
300 struct group *getgrnam(const char *name)
302 struct dirent *dent;
303 pw_tls_t *p;
304 DIR *query;
305 int err;
306 int fd;
308 PRINT(("%s()\n", __FUNCTION__));
309 p = get_pw_tls();
310 if (!p) {
311 /* we are really bork */
312 __set_errno(ENOMEM);
313 return NULL;
316 if (!name || strlen(name) > GR_MAX_NAME) {
317 __set_errno(EINVAL);
318 return NULL;
320 /* reusing path */
321 sprintf(p->grfile, QT_GR_NAM, name);
322 query = fs_open_query(boot_device, p->grfile, 0);
323 PRINT(("q: %p\n", query));
324 if (!query)
325 return NULL;
327 dent = fs_read_query(query);
328 if (!dent) {
329 fs_close_query(query);
330 return NULL;
332 fd = dentopen(dent, p->grfile);
333 fs_close_query(query);
334 if (fd < B_OK)
335 return NULL;
336 err = fill_grent_from_fd(fd, &p->grent, p->grbuff, GRBUFFSZ);
337 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err));
338 close(fd);
339 if (err)
340 return NULL;
341 return &p->grent;
346 /* user stuff */
348 int fill_pwent_default(struct passwd *pwbuf)
350 PRINT(("%s()\n", __FUNCTION__));
351 return ENOENT; /* hmm no we don't exist! */
352 pwbuf->pw_gid = 1000;
353 pwbuf->pw_uid = 1000;
354 pwbuf->pw_name = "baron";
355 pwbuf->pw_passwd = "*";
356 pwbuf->pw_dir = "/var/tmp";
357 pwbuf->pw_shell = "/bin/false";
358 pwbuf->pw_gecos = "Unknown User";
359 return 0;
362 int fill_pwent_from_fd(int fd, struct passwd *pwbuf, char *buf, size_t buflen)
364 ssize_t left;
365 ssize_t len;
366 PRINT(("%s()\n", __FUNCTION__));
367 left = buflen;
368 if (left <= 0)
369 return ERANGE;
371 len = fs_read_attr(fd, B_PW_GID, B_INT32_TYPE, 0LL, &pwbuf->pw_gid, sizeof(gid_t));
372 if (len < 0)
373 return fill_pwent_default(pwbuf);
374 PRINT(("%s: got gid\n", __FUNCTION__));
376 len = fs_read_attr(fd, B_PW_UID, B_INT32_TYPE, 0LL, &pwbuf->pw_uid, sizeof(uid_t));
377 if (len < 0)
378 return fill_pwent_default(pwbuf);
379 PRINT(("%s: got uid\n", __FUNCTION__));
381 if (left < PW_MAX_NAME + 1)
382 return ERANGE;
383 len = fs_read_attr(fd, B_PW_NAME, B_STRING_TYPE, 0LL, buf, PW_MAX_NAME);
384 if (len < 0)
385 return fill_pwent_default(pwbuf);
386 pwbuf->pw_name = buf;
387 buf[len] = '\0';
388 left -= len + 1;
389 buf += len + 1;
390 PRINT(("%s: got name\n", __FUNCTION__));
392 if (left < PW_MAX_DIR + 1)
393 return ERANGE;
394 len = fs_read_attr(fd, B_PW_DIR, B_STRING_TYPE, 0LL, buf, PW_MAX_DIR);
395 if (len < 0)
396 return fill_pwent_default(pwbuf);
397 pwbuf->pw_dir = buf;
398 buf[len] = '\0';
399 left -= len + 1;
400 buf += len + 1;
401 PRINT(("%s: got dir\n", __FUNCTION__));
403 if (left < PW_MAX_SHELL + 1)
404 return ERANGE;
405 len = fs_read_attr(fd, B_PW_SHELL, B_STRING_TYPE, 0LL, buf, PW_MAX_SHELL);
406 if (len < 0)
407 return fill_pwent_default(pwbuf);
408 pwbuf->pw_shell = buf;
409 buf[len] = '\0';
410 left -= len + 1;
411 buf += len + 1;
412 PRINT(("%s: got shell\n", __FUNCTION__));
414 if (left < PW_MAX_GECOS + 1)
415 return ERANGE;
416 len = fs_read_attr(fd, B_PW_GECOS, B_STRING_TYPE, 0LL, buf, PW_MAX_GECOS);
417 if (len < 0)
418 return fill_pwent_default(pwbuf);
419 pwbuf->pw_gecos = buf;
420 buf[len] = '\0';
421 left -= len + 1;
422 buf += len + 1;
423 PRINT(("%s: got gecos\n", __FUNCTION__));
425 if (left < PW_MAX_PASSWD + 1)
426 return ERANGE;
427 len = fs_read_attr(fd, B_PW_PASSWD, B_STRING_TYPE, 0LL, buf, PW_MAX_PASSWD);
428 if (len < 0) {
429 buf[0] = '*'; /* no pass set */
430 len = 1;
432 pwbuf->pw_passwd = buf;
433 buf[len] = '\0';
434 left -= len + 1;
435 buf += len + 1;
436 PRINT(("%s: got passwd\n", __FUNCTION__));
438 return 0;
443 void setpwent(void)
445 pw_tls_t *p;
446 p = get_pw_tls();
447 PRINT(("%s()\n", __FUNCTION__));
448 if (p->pwent_query) /* clumsy apps */
449 fs_close_query(p->pwent_query);
450 p->pwent_query = fs_open_query(boot_device, Q_PW_ALL, 0);
451 PRINT(("pwq: %p\n", p->pwent_query));
452 p->pwidx = 0;
455 void endpwent(void)
457 pw_tls_t *p;
458 PRINT(("%s()\n", __FUNCTION__));
459 p = get_pw_tls();
461 if (p->pwent_query)
462 fs_close_query(p->pwent_query);
463 p->pwent_query = NULL;
464 p->pwidx = -1;
468 /* this conforms to the linux getpwent_r (there are several protos for that one... crap) */
469 /* note the FILE * based version is not supported as it makes no sense here */
470 int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp)
472 pw_tls_t *p;
473 int err;
474 int fd;
475 struct dirent *dent;
476 PRINT(("%s()\n", __FUNCTION__));
477 p = get_pw_tls();
478 if (!p)
479 return ENOMEM;
480 PRINT(("getpwent_r: pwq = %p, idx = %d\n", p->pwent_query, p->pwidx));
481 if (!p->pwent_query)
482 setpwent(); /* y0u clumsy app! */
483 if (!p->pwent_query)
484 return EIO; /* something happened... */
485 __set_errno(0);
486 dent = fs_read_query(p->pwent_query);
487 *pwbufp = NULL;
488 if (!dent) {
489 /* found nothing on first iteration ? */
490 if (p->pwidx == 0) {
491 if (fill_pwent_default(pwbuf) < 0)
492 return -1;
493 *pwbufp = pwbuf;
494 p->pwidx++;
496 return 0;
498 fd = dentopen(dent, p->pwfile);
499 if (fd < B_OK)
500 return errno?errno:-1;
501 err = fill_pwent_from_fd(fd, pwbuf, buf, buflen);
502 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err));
503 close(fd);
504 if (err)
505 return err;
506 p->pwidx++;
507 *pwbufp = pwbuf;
508 return 0;
511 struct passwd *getpwent(void)
513 pw_tls_t *p;
514 struct passwd *ent;
515 int err;
516 PRINT(("%s()\n", __FUNCTION__));
517 p = get_pw_tls();
518 if (!p) {
519 /* we are really bork */
520 __set_errno(ENOMEM);
521 return NULL;
523 err = getpwent_r(&p->pwent, p->pwbuff, PWBUFFSZ, &ent);
524 if (err < 0) {
525 __set_errno(err);
526 return NULL;
528 if (!ent)
529 return NULL;
530 PRINT(("getpwent(); returning entry for %s\n", ent->pw_name));
531 return ent;
534 /* by gid */
535 struct passwd *getpwuid(uid_t uid)
537 struct dirent *dent;
538 pw_tls_t *p;
539 DIR *query;
540 int err;
541 int fd;
543 PRINT(("%s(%d)\n", __FUNCTION__, uid));
544 p = get_pw_tls();
545 if (!p) {
546 /* we are really bork */
547 __set_errno(ENOMEM);
548 return NULL;
551 /* reusing path */
552 sprintf(p->pwfile, QT_PW_UID, uid);
553 PRINT(("%s: query(%s)\n", __FUNCTION__, p->pwfile));
554 query = fs_open_query(boot_device, p->pwfile, 0);
555 PRINT(("q: %p\n", query));
556 if (!query)
557 return NULL;
559 dent = fs_read_query(query);
560 if (!dent) {
561 fs_close_query(query);
562 return NULL;
564 fd = dentopen(dent, p->pwfile);
565 fs_close_query(query);
566 if (fd < B_OK)
567 return NULL;
568 err = fill_pwent_from_fd(fd, &p->pwent, p->pwbuff, PWBUFFSZ);
569 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err));
570 close(fd);
571 if (err)
572 return NULL;
573 return &p->pwent;
577 /* by name */
578 struct passwd *getpwnam(const char *name)
580 struct dirent *dent;
581 pw_tls_t *p;
582 DIR *query;
583 int err;
584 int fd;
586 PRINT(("%s(%s)\n", __FUNCTION__, name));
587 p = get_pw_tls();
588 if (!p) {
589 /* we are really bork */
590 __set_errno(ENOMEM);
591 return NULL;
594 if (!name || strlen(name) > PW_MAX_NAME) {
595 __set_errno(EINVAL);
596 return NULL;
598 /* reusing path */
599 sprintf(p->pwfile, QT_PW_NAM, name);
600 PRINT(("%s: query(%s)\n", __FUNCTION__, p->pwfile));
601 query = fs_open_query(boot_device, p->pwfile, 0);
602 PRINT(("q: %p\n", query));
603 if (!query)
604 return NULL;
606 dent = fs_read_query(query);
607 if (!dent) {
608 fs_close_query(query);
609 return NULL;
611 PRINT(("%s: dentopen()\n", __FUNCTION__));
612 fd = dentopen(dent, p->pwfile);
613 fs_close_query(query);
614 if (fd < B_OK)
615 return NULL;
616 err = fill_pwent_from_fd(fd, &p->pwent, p->pwbuff, PWBUFFSZ);
617 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err));
618 close(fd);
619 if (err)
620 return NULL;
621 return &p->pwent;
625 void __init_pwd_backend(void)
627 /* dev_t for the boot volume */
628 boot_device = dev_for_path("/boot");
629 /* get us an id for holding thread-specific data */
630 pw_tls_id = tls_allocate();
634 void __fini_pwd_backend(void)
640 #endif /* REAL_MULTIUSER */