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 /* 24 * Some notes. 25 * Users are stored in an fs node (not necessarily a regular file, 26 * that could be a dir, even the user's home dir, 27 * though we should be careful as they are owned by users. 28 */ 29 30 31 #define GR_MAX_NAME 32 32 33 #define PW_MAX_NAME 32 34 #define PW_MAX_DIR B_PATH_NAME_LENGTH 35 #define PW_MAX_GECOS 128 36 #define PW_MAX_PASSWD 32 37 #define PW_MAX_SHELL B_PATH_NAME_LENGTH 38 39 /* should be more than enough :) */ 40 #define GRBUFFSZ (GR_MAX_NAME + 2) 41 #define PWBUFFSZ (PW_MAX_NAME + PW_MAX_DIR + PW_MAX_GECOS + PW_MAX_PASSWD + PW_MAX_SHELL + 4) 42 43 44 /* attribute names we use to store groups & users. */ 45 /* pets nm & strings */ 46 47 static const char *B_GR_GID = "sys:group:gid"; 48 static const char *B_GR_NAME = "sys:group:name"; 49 //static const char *B_GR_PASSWD = "sys:group:passwd"; 50 51 static const char *B_PW_DIR = "sys:user:dir"; 52 static const char *B_PW_GECOS = "sys:user:fullname"; 53 static const char *B_PW_GID = "sys:user:gid"; 54 static const char *B_PW_NAME = "sys:user:name"; 55 static const char *B_PW_PASSWD = "sys:user:passwd"; 56 static const char *B_PW_SHELL = "sys:user:shell"; 57 static const char *B_PW_UID = "sys:user:uid"; 58 59 /* queries */ 60 static const char *Q_GR_ALL = "sys:group:gid>-1"; 61 static const char *QT_GR_GID = "sys:group:gid==%d"; 62 static const char *QT_GR_NAM = "sys:group:name==\"%s\""; 63 static const char *Q_PW_ALL = "sys:user:uid>-1"; 64 static const char *QT_PW_UID = "sys:user:uid==%d"; 65 static const char *QT_PW_NAM = "sys:user:name==\"%s\""; 66 67 extern void __init_pwd_stuff(void); 68 extern void __fini_pwd_stuff(void); 69 70 static char *default_gr_members[] = { /*"baron",*/ NULL }; 71 72 static dev_t boot_device; 73 74 /* TLS stuff */ 75 76 static int32 pw_tls_id; 77 78 typedef struct pw_tls { 79 DIR *grent_query; 80 DIR *pwent_query; 81 82 int gridx; 83 int pwidx; 84 85 char grfile[B_PATH_NAME_LENGTH+1]; /* current group's cached file path */ 86 char pwfile[B_PATH_NAME_LENGTH+1]; /* current user's cached file path */ 87 88 struct group grent; 89 char grbuff[GRBUFFSZ]; /* XXX: merge with pwbuff ? */ 90 91 struct passwd pwent; 92 char pwbuff[PWBUFFSZ]; 93 } pw_tls_t; 94 95 struct pw_tls *get_pw_tls(void) 96 { 97 pw_tls_t *p = (pw_tls_t *)tls_get(pw_tls_id); 98 PRINT(("%s()\n", __FUNCTION__)); 99 100 if (!p) { 101 p = (pw_tls_t *)malloc(sizeof(pw_tls_t)); 102 if (!p) 103 return NULL; 104 memset(p, 0, sizeof(pw_tls_t)); 105 p->grent_query = NULL; 106 p->pwent_query = NULL; 107 tls_set(pw_tls_id, p); 108 } 109 return p; 110 } 111 112 /* fill the path from the dirent and open() */ 113 int dentopen(struct dirent *dent, char *path) 114 { 115 int err; 116 PRINT(("%s({%ld, %Ld, %ld, %Ld, %s}, )\n", __FUNCTION__, dent->d_pdev, dent->d_pino, dent->d_dev, dent->d_ino, dent->d_name)); 117 dent->d_dev = boot_device; 118 err = get_path_for_dirent(dent, path, B_PATH_NAME_LENGTH); 119 if ((err < 0) || (path[0] != '/')) { 120 errno = err; 121 return -1; 122 } 123 PRINT(("%s: open(%s)\n", __FUNCTION__, path)); 124 return open(path, O_RDONLY); 125 } 126 127 /* group stuff */ 128 129 int fill_grent_default(struct group *gbuf) 130 { 131 PRINT(("%s()\n", __FUNCTION__)); 132 gbuf->gr_gid = 1000; 133 gbuf->gr_name = gbuf->gr_gid?"users":"wheel"; 134 gbuf->gr_passwd = ""; 135 gbuf->gr_mem = default_gr_members; 136 return 0; 137 } 138 139 int fill_grent_from_fd(int fd, struct group *gbuf, char *buf, size_t buflen) 140 { 141 size_t left; 142 ssize_t len; 143 left = buflen; 144 len = fs_read_attr(fd, B_GR_GID, B_INT32_TYPE, 0LL, &gbuf->gr_gid, sizeof(gid_t)); 145 if (len < 0) 146 return fill_grent_default(gbuf); 147 PRINT(("%s: got gid\n", __FUNCTION__)); 148 gbuf->gr_passwd = ""; 149 gbuf->gr_mem = default_gr_members; 150 151 if (left < GR_MAX_NAME + 1) 152 return ERANGE; 153 len = fs_read_attr(fd, B_GR_NAME, B_STRING_TYPE, 0LL, buf, GR_MAX_NAME); 154 if (len < 0) 155 return fill_grent_default(gbuf); 156 gbuf->gr_name = buf; 157 buf[len] = '\0'; 158 left -= len + 1; 159 buf += len + 1; 160 PRINT(("%s: got name\n", __FUNCTION__)); 161 return 0; 162 } 163 164 void setgrent(void) 165 { 166 pw_tls_t *p; 167 p = get_pw_tls(); 168 PRINT(("%s()\n", __FUNCTION__)); 169 if (p->grent_query) /* clumsy apps */ 170 fs_close_query(p->grent_query); 171 p->grent_query = fs_open_query(boot_device, Q_GR_ALL, 0); 172 PRINT(("pwq: %p\n", p->grent_query)); 173 p->gridx = 0; 174 } 175 176 void endgrent(void) 177 { 178 pw_tls_t *p; 179 PRINT(("%s()\n", __FUNCTION__)); 180 p = get_pw_tls(); 181 182 if (p->grent_query) 183 fs_close_query(p->grent_query); 184 p->grent_query = NULL; 185 p->gridx = -1; 186 } 187 188 189 /* this conforms to the linux getgrent_r (there are several protos for that one... crap) */ 190 /* note the FILE * based version is not supported as it makes no sense here */ 191 int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) 192 { 193 pw_tls_t *p; 194 int err; 195 int fd; 196 struct dirent *dent; 197 PRINT(("%s()\n", __FUNCTION__)); 198 p = get_pw_tls(); 199 if (!p) 200 return ENOMEM; 201 PRINT(("getgrent_r: grq = %p, idx = %d\n", p->grent_query, p->gridx)); 202 if (!p->grent_query) 203 setgrent(); /* y0u clumsy app! */ 204 if (!p->grent_query) 205 return EIO; /* something happened... */ 206 errno = 0; 207 dent = fs_read_query(p->grent_query); 208 *gbufp = NULL; 209 if (!dent) { 210 /* found nothing on first iteration ? */ 211 if (p->gridx == 0) { 212 if (fill_grent_default(gbuf) < 0) 213 return -1; 214 *gbufp = gbuf; 215 p->gridx++; 216 } 217 return 0; 218 } 219 fd = dentopen(dent, p->grfile); 220 if (fd < B_OK) 221 return errno?errno:-1; 222 err = fill_grent_from_fd(fd, gbuf, buf, buflen); 223 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err)); 224 close(fd); 225 if (err) 226 return err; 227 p->gridx++; 228 *gbufp = gbuf; 229 return 0; 230 } 231 232 struct group *getgrent(void) 233 { 234 pw_tls_t *p; 235 struct group *ent; 236 int err; 237 PRINT(("%s()\n", __FUNCTION__)); 238 p = get_pw_tls(); 239 if (!p) { 240 /* we are really bork */ 241 errno = ENOMEM; 242 return NULL; 243 } 244 err = getgrent_r(&p->grent, p->grbuff, GRBUFFSZ, &ent); 245 if (err < 0) { 246 errno = err; 247 return NULL; 248 } 249 if (!ent) 250 return NULL; 251 PRINT(("getgrent(); returning entry for %s\n", ent->gr_name)); 252 return ent; 253 } 254 255 /* by gid */ 256 struct group *getgrgid(gid_t gid) 257 { 258 struct dirent *dent; 259 pw_tls_t *p; 260 DIR *query; 261 int err; 262 int fd; 263 264 PRINT(("%s()\n", __FUNCTION__)); 265 p = get_pw_tls(); 266 if (!p) { 267 /* we are really bork */ 268 errno = ENOMEM; 269 return NULL; 270 } 271 272 /* reusing path */ 273 sprintf(p->grfile, QT_GR_GID, gid); 274 query = fs_open_query(boot_device, p->grfile, 0); 275 PRINT(("q: %p\n", query)); 276 if (!query) 277 return NULL; 278 279 dent = fs_read_query(query); 280 if (!dent) { 281 fs_close_query(query); 282 return NULL; 283 } 284 fd = dentopen(dent, p->grfile); 285 fs_close_query(query); 286 if (fd < B_OK) 287 return NULL; 288 err = fill_grent_from_fd(fd, &p->grent, p->grbuff, GRBUFFSZ); 289 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err)); 290 close(fd); 291 if (err) 292 return NULL; 293 return &p->grent; 294 295 } 296 297 /* by name */ 298 struct group *getgrnam(const char *name) 299 { 300 struct dirent *dent; 301 pw_tls_t *p; 302 DIR *query; 303 int err; 304 int fd; 305 306 PRINT(("%s()\n", __FUNCTION__)); 307 p = get_pw_tls(); 308 if (!p) { 309 /* we are really bork */ 310 errno = ENOMEM; 311 return NULL; 312 } 313 314 if (!name || strlen(name) > GR_MAX_NAME) { 315 errno = EINVAL; 316 return NULL; 317 } 318 /* reusing path */ 319 sprintf(p->grfile, QT_GR_NAM, name); 320 query = fs_open_query(boot_device, p->grfile, 0); 321 PRINT(("q: %p\n", query)); 322 if (!query) 323 return NULL; 324 325 dent = fs_read_query(query); 326 if (!dent) { 327 fs_close_query(query); 328 return NULL; 329 } 330 fd = dentopen(dent, p->grfile); 331 fs_close_query(query); 332 if (fd < B_OK) 333 return NULL; 334 err = fill_grent_from_fd(fd, &p->grent, p->grbuff, GRBUFFSZ); 335 PRINT(("%s: fill_grent_from_fd = %d\n", __FUNCTION__, err)); 336 close(fd); 337 if (err) 338 return NULL; 339 return &p->grent; 340 341 } 342 343 344 /* user stuff */ 345 346 int fill_pwent_default(struct passwd *pwbuf) 347 { 348 PRINT(("%s()\n", __FUNCTION__)); 349 return ENOENT; /* hmm no we don't exist! */ 350 pwbuf->pw_gid = 1000; 351 pwbuf->pw_uid = 1000; 352 pwbuf->pw_name = "baron"; 353 pwbuf->pw_passwd = "*"; 354 pwbuf->pw_dir = "/var/tmp"; 355 pwbuf->pw_shell = "/bin/false"; 356 pwbuf->pw_gecos = "Unknown User"; 357 return 0; 358 } 359 360 int fill_pwent_from_fd(int fd, struct passwd *pwbuf, char *buf, size_t buflen) 361 { 362 ssize_t left; 363 ssize_t len; 364 PRINT(("%s()\n", __FUNCTION__)); 365 left = buflen; 366 if (left <= 0) 367 return ERANGE; 368 369 len = fs_read_attr(fd, B_PW_GID, B_INT32_TYPE, 0LL, &pwbuf->pw_gid, sizeof(gid_t)); 370 if (len < 0) 371 return fill_pwent_default(pwbuf); 372 PRINT(("%s: got gid\n", __FUNCTION__)); 373 374 len = fs_read_attr(fd, B_PW_UID, B_INT32_TYPE, 0LL, &pwbuf->pw_uid, sizeof(uid_t)); 375 if (len < 0) 376 return fill_pwent_default(pwbuf); 377 PRINT(("%s: got uid\n", __FUNCTION__)); 378 379 if (left < PW_MAX_NAME + 1) 380 return ERANGE; 381 len = fs_read_attr(fd, B_PW_NAME, B_STRING_TYPE, 0LL, buf, PW_MAX_NAME); 382 if (len < 0) 383 return fill_pwent_default(pwbuf); 384 pwbuf->pw_name = buf; 385 buf[len] = '\0'; 386 left -= len + 1; 387 buf += len + 1; 388 PRINT(("%s: got name\n", __FUNCTION__)); 389 390 if (left < PW_MAX_DIR + 1) 391 return ERANGE; 392 len = fs_read_attr(fd, B_PW_DIR, B_STRING_TYPE, 0LL, buf, PW_MAX_DIR); 393 if (len < 0) 394 return fill_pwent_default(pwbuf); 395 pwbuf->pw_dir = buf; 396 buf[len] = '\0'; 397 left -= len + 1; 398 buf += len + 1; 399 PRINT(("%s: got dir\n", __FUNCTION__)); 400 401 if (left < PW_MAX_SHELL + 1) 402 return ERANGE; 403 len = fs_read_attr(fd, B_PW_SHELL, B_STRING_TYPE, 0LL, buf, PW_MAX_SHELL); 404 if (len < 0) 405 return fill_pwent_default(pwbuf); 406 pwbuf->pw_shell = buf; 407 buf[len] = '\0'; 408 left -= len + 1; 409 buf += len + 1; 410 PRINT(("%s: got shell\n", __FUNCTION__)); 411 412 if (left < PW_MAX_GECOS + 1) 413 return ERANGE; 414 len = fs_read_attr(fd, B_PW_GECOS, B_STRING_TYPE, 0LL, buf, PW_MAX_GECOS); 415 if (len < 0) 416 return fill_pwent_default(pwbuf); 417 pwbuf->pw_gecos = buf; 418 buf[len] = '\0'; 419 left -= len + 1; 420 buf += len + 1; 421 PRINT(("%s: got gecos\n", __FUNCTION__)); 422 423 if (left < PW_MAX_PASSWD + 1) 424 return ERANGE; 425 len = fs_read_attr(fd, B_PW_PASSWD, B_STRING_TYPE, 0LL, buf, PW_MAX_PASSWD); 426 if (len < 0) { 427 buf[0] = '*'; /* no pass set */ 428 len = 1; 429 } 430 pwbuf->pw_passwd = buf; 431 buf[len] = '\0'; 432 left -= len + 1; 433 buf += len + 1; 434 PRINT(("%s: got passwd\n", __FUNCTION__)); 435 436 return 0; 437 } 438 439 440 441 void setpwent(void) 442 { 443 pw_tls_t *p; 444 p = get_pw_tls(); 445 PRINT(("%s()\n", __FUNCTION__)); 446 if (p->pwent_query) /* clumsy apps */ 447 fs_close_query(p->pwent_query); 448 p->pwent_query = fs_open_query(boot_device, Q_PW_ALL, 0); 449 PRINT(("pwq: %p\n", p->pwent_query)); 450 p->pwidx = 0; 451 } 452 453 void endpwent(void) 454 { 455 pw_tls_t *p; 456 PRINT(("%s()\n", __FUNCTION__)); 457 p = get_pw_tls(); 458 459 if (p->pwent_query) 460 fs_close_query(p->pwent_query); 461 p->pwent_query = NULL; 462 p->pwidx = -1; 463 } 464 465 466 /* this conforms to the linux getpwent_r (there are several protos for that one... crap) */ 467 /* note the FILE * based version is not supported as it makes no sense here */ 468 int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) 469 { 470 pw_tls_t *p; 471 int err; 472 int fd; 473 struct dirent *dent; 474 PRINT(("%s()\n", __FUNCTION__)); 475 p = get_pw_tls(); 476 if (!p) 477 return ENOMEM; 478 PRINT(("getpwent_r: pwq = %p, idx = %d\n", p->pwent_query, p->pwidx)); 479 if (!p->pwent_query) 480 setpwent(); /* y0u clumsy app! */ 481 if (!p->pwent_query) 482 return EIO; /* something happened... */ 483 errno = 0; 484 dent = fs_read_query(p->pwent_query); 485 *pwbufp = NULL; 486 if (!dent) { 487 /* found nothing on first iteration ? */ 488 if (p->pwidx == 0) { 489 if (fill_pwent_default(pwbuf) < 0) 490 return -1; 491 *pwbufp = pwbuf; 492 p->pwidx++; 493 } 494 return 0; 495 } 496 fd = dentopen(dent, p->pwfile); 497 if (fd < B_OK) 498 return errno?errno:-1; 499 err = fill_pwent_from_fd(fd, pwbuf, buf, buflen); 500 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err)); 501 close(fd); 502 if (err) 503 return err; 504 p->pwidx++; 505 *pwbufp = pwbuf; 506 return 0; 507 } 508 509 struct passwd *getpwent(void) 510 { 511 pw_tls_t *p; 512 struct passwd *ent; 513 int err; 514 PRINT(("%s()\n", __FUNCTION__)); 515 p = get_pw_tls(); 516 if (!p) { 517 /* we are really bork */ 518 errno = ENOMEM; 519 return NULL; 520 } 521 err = getpwent_r(&p->pwent, p->pwbuff, PWBUFFSZ, &ent); 522 if (err < 0) { 523 errno = err; 524 return NULL; 525 } 526 if (!ent) 527 return NULL; 528 PRINT(("getpwent(); returning entry for %s\n", ent->pw_name)); 529 return ent; 530 } 531 532 /* by gid */ 533 struct passwd *getpwuid(uid_t uid) 534 { 535 struct dirent *dent; 536 pw_tls_t *p; 537 DIR *query; 538 int err; 539 int fd; 540 541 PRINT(("%s(%d)\n", __FUNCTION__, uid)); 542 p = get_pw_tls(); 543 if (!p) { 544 /* we are really bork */ 545 errno = ENOMEM; 546 return NULL; 547 } 548 549 /* reusing path */ 550 sprintf(p->pwfile, QT_PW_UID, uid); 551 PRINT(("%s: query(%s)\n", __FUNCTION__, p->pwfile)); 552 query = fs_open_query(boot_device, p->pwfile, 0); 553 PRINT(("q: %p\n", query)); 554 if (!query) 555 return NULL; 556 557 dent = fs_read_query(query); 558 if (!dent) { 559 fs_close_query(query); 560 return NULL; 561 } 562 fd = dentopen(dent, p->pwfile); 563 fs_close_query(query); 564 if (fd < B_OK) 565 return NULL; 566 err = fill_pwent_from_fd(fd, &p->pwent, p->pwbuff, PWBUFFSZ); 567 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err)); 568 close(fd); 569 if (err) 570 return NULL; 571 return &p->pwent; 572 573 } 574 575 /* by name */ 576 struct passwd *getpwnam(const char *name) 577 { 578 struct dirent *dent; 579 pw_tls_t *p; 580 DIR *query; 581 int err; 582 int fd; 583 584 PRINT(("%s(%s)\n", __FUNCTION__, name)); 585 p = get_pw_tls(); 586 if (!p) { 587 /* we are really bork */ 588 errno = ENOMEM; 589 return NULL; 590 } 591 592 if (!name || strlen(name) > PW_MAX_NAME) { 593 errno = EINVAL; 594 return NULL; 595 } 596 /* reusing path */ 597 sprintf(p->pwfile, QT_PW_NAM, name); 598 PRINT(("%s: query(%s)\n", __FUNCTION__, p->pwfile)); 599 query = fs_open_query(boot_device, p->pwfile, 0); 600 PRINT(("q: %p\n", query)); 601 if (!query) 602 return NULL; 603 604 dent = fs_read_query(query); 605 if (!dent) { 606 fs_close_query(query); 607 return NULL; 608 } 609 PRINT(("%s: dentopen()\n", __FUNCTION__)); 610 fd = dentopen(dent, p->pwfile); 611 fs_close_query(query); 612 if (fd < B_OK) 613 return NULL; 614 err = fill_pwent_from_fd(fd, &p->pwent, p->pwbuff, PWBUFFSZ); 615 PRINT(("%s: fill_pwent_from_fd = %d\n", __FUNCTION__, err)); 616 close(fd); 617 if (err) 618 return NULL; 619 return &p->pwent; 620 621 } 622 623 624 void __init_pwd_stuff(void) 625 //void _multiuser_init(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 void __fini_pwd_stuff(void) 634 //void _multiuser_fini(void) 635 { 636 637 } 638 639 640 #endif /* REAL_MULTIUSER */ 641 642