1 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 */ 7 8 //#ifdef REAL_MULTIUSER 9 #if 1 10 11 #include <pwd.h> 12 #include <grp.h> 13 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> 22 23 #include <errno_private.h> 24 25 /* 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. 30 */ 31 32 33 #define GR_MAX_NAME 32 34 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 40 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) 44 45 46 /* attribute names we use to store groups & users. */ 47 /* pets nm & strings */ 48 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"; 52 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"; 60 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\""; 68 69 extern void __init_pwd_stuff(void); 70 extern void __fini_pwd_stuff(void); 71 72 static char *default_gr_members[] = { /*"baron",*/ NULL }; 73 74 static dev_t boot_device; 75 76 /* TLS stuff */ 77 78 static int32 pw_tls_id; 79 80 typedef struct pw_tls { 81 DIR *grent_query; 82 DIR *pwent_query; 83 84 int gridx; 85 int pwidx; 86 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 */ 89 90 struct group grent; 91 char grbuff[GRBUFFSZ]; /* XXX: merge with pwbuff ? */ 92 93 struct passwd pwent; 94 char pwbuff[PWBUFFSZ]; 95 } pw_tls_t; 96 97 struct pw_tls *get_pw_tls(void) 98 { 99 pw_tls_t *p = (pw_tls_t *)tls_get(pw_tls_id); 100 PRINT(("%s()\n", __FUNCTION__)); 101 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); 110 } 111 return p; 112 } 113 114 /* fill the path from the dirent and open() */ 115 int dentopen(struct dirent *dent, char *path) 116 { 117 int err; 118 PRINT(("%s({%ld, %lld, %ld, %lld, %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; 124 } 125 PRINT(("%s: open(%s)\n", __FUNCTION__, path)); 126 return open(path, O_RDONLY); 127 } 128 129 /* group stuff */ 130 131 int fill_grent_default(struct group *gbuf) 132 { 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; 139 } 140 141 int fill_grent_from_fd(int fd, struct group *gbuf, char *buf, size_t buflen) 142 { 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; 152 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; 164 } 165 166 void setgrent(void) 167 { 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; 176 } 177 178 void endgrent(void) 179 { 180 pw_tls_t *p; 181 PRINT(("%s()\n", __FUNCTION__)); 182 p = get_pw_tls(); 183 184 if (p->grent_query) 185 fs_close_query(p->grent_query); 186 p->grent_query = NULL; 187 p->gridx = -1; 188 } 189 190 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) 194 { 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++; 218 } 219 return 0; 220 } 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; 232 } 233 234 struct group *getgrent(void) 235 { 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; 245 } 246 err = getgrent_r(&p->grent, p->grbuff, GRBUFFSZ, &ent); 247 if (err < 0) { 248 __set_errno(err); 249 return NULL; 250 } 251 if (!ent) 252 return NULL; 253 PRINT(("getgrent(); returning entry for %s\n", ent->gr_name)); 254 return ent; 255 } 256 257 /* by gid */ 258 struct group *getgrgid(gid_t gid) 259 { 260 struct dirent *dent; 261 pw_tls_t *p; 262 DIR *query; 263 int err; 264 int fd; 265 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; 272 } 273 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; 280 281 dent = fs_read_query(query); 282 if (!dent) { 283 fs_close_query(query); 284 return NULL; 285 } 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; 296 297 } 298 299 /* by name */ 300 struct group *getgrnam(const char *name) 301 { 302 struct dirent *dent; 303 pw_tls_t *p; 304 DIR *query; 305 int err; 306 int fd; 307 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; 314 } 315 316 if (!name || strlen(name) > GR_MAX_NAME) { 317 __set_errno(EINVAL); 318 return NULL; 319 } 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; 326 327 dent = fs_read_query(query); 328 if (!dent) { 329 fs_close_query(query); 330 return NULL; 331 } 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; 342 343 } 344 345 346 /* user stuff */ 347 348 int fill_pwent_default(struct passwd *pwbuf) 349 { 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; 360 } 361 362 int fill_pwent_from_fd(int fd, struct passwd *pwbuf, char *buf, size_t buflen) 363 { 364 ssize_t left; 365 ssize_t len; 366 PRINT(("%s()\n", __FUNCTION__)); 367 left = buflen; 368 if (left <= 0) 369 return ERANGE; 370 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__)); 375 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__)); 380 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__)); 391 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__)); 402 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__)); 413 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__)); 424 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; 431 } 432 pwbuf->pw_passwd = buf; 433 buf[len] = '\0'; 434 left -= len + 1; 435 buf += len + 1; 436 PRINT(("%s: got passwd\n", __FUNCTION__)); 437 438 return 0; 439 } 440 441 442 443 void setpwent(void) 444 { 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; 453 } 454 455 void endpwent(void) 456 { 457 pw_tls_t *p; 458 PRINT(("%s()\n", __FUNCTION__)); 459 p = get_pw_tls(); 460 461 if (p->pwent_query) 462 fs_close_query(p->pwent_query); 463 p->pwent_query = NULL; 464 p->pwidx = -1; 465 } 466 467 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) 471 { 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++; 495 } 496 return 0; 497 } 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; 509 } 510 511 struct passwd *getpwent(void) 512 { 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; 522 } 523 err = getpwent_r(&p->pwent, p->pwbuff, PWBUFFSZ, &ent); 524 if (err < 0) { 525 __set_errno(err); 526 return NULL; 527 } 528 if (!ent) 529 return NULL; 530 PRINT(("getpwent(); returning entry for %s\n", ent->pw_name)); 531 return ent; 532 } 533 534 /* by gid */ 535 struct passwd *getpwuid(uid_t uid) 536 { 537 struct dirent *dent; 538 pw_tls_t *p; 539 DIR *query; 540 int err; 541 int fd; 542 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; 549 } 550 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; 558 559 dent = fs_read_query(query); 560 if (!dent) { 561 fs_close_query(query); 562 return NULL; 563 } 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; 574 575 } 576 577 /* by name */ 578 struct passwd *getpwnam(const char *name) 579 { 580 struct dirent *dent; 581 pw_tls_t *p; 582 DIR *query; 583 int err; 584 int fd; 585 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; 592 } 593 594 if (!name || strlen(name) > PW_MAX_NAME) { 595 __set_errno(EINVAL); 596 return NULL; 597 } 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; 605 606 dent = fs_read_query(query); 607 if (!dent) { 608 fs_close_query(query); 609 return NULL; 610 } 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; 622 623 } 624 625 void __init_pwd_backend(void) 626 { 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(); 631 } 632 633 /* 634 void __fini_pwd_backend(void) 635 { 636 637 } 638 */ 639 640 #endif /* REAL_MULTIUSER */ 641 642