00001
00002
00003
00004
00005 #include <sys/stat.h>
00006 #include <sys/types.h>
00007 #include <u/libu_conf.h>
00008 #include <u/libu.h>
00009 #include <toolbox/hmap.h>
00010 #include <toolbox/pwd.h>
00011
00012
00013 static int u_pwd_db_new (u_pwd_t *pwd);
00014 static int u_pwd_db_term (u_pwd_t *pwd);
00015 static int u_pwd_db_load (u_pwd_t *pwd);
00016 static int u_pwd_db_push (u_pwd_t *pwd, u_pwd_rec_t *rec);
00017 static void __hmap_pwd_rec_free (void *val);
00018
00019
00020 static int u_pwd_load (u_pwd_t *pwd);
00021 static int u_pwd_need_reload (u_pwd_t *pwd);
00022
00023
00024 static int u_pwd_rec_new (const char *user, const char *pass,
00025 const char *opaque, u_pwd_rec_t **prec);
00026 static int u_pwd_retr_mem (u_pwd_t *pwd, const char *user,
00027 u_pwd_rec_t **prec);
00028 static int u_pwd_retr_res (u_pwd_t *pwd, const char *user,
00029 u_pwd_rec_t **prec);
00030
00031
00032 static int u_pwd_res_open (u_pwd_t *pwd);
00033 static void u_pwd_res_close (u_pwd_t *pwd);
00034
00035
00036 static int __file_open (const char *path, void **pfp);
00037 static void __file_close (void *fp);
00038 static char *__file_load (char *str, int size, void *fp);
00039 static int __file_notify (const char *path, time_t last_update,
00040 time_t *pnew_update);
00041
00042
00043 struct u_pwd_s
00044 {
00045 void *res_handler;
00046 char res_uri[U_FILENAME_MAX + 1];
00047
00048 size_t hash_len;
00049 u_pwd_hash_cb_t cb_hash;
00050
00051 u_pwd_open_cb_t cb_open;
00052 u_pwd_load_cb_t cb_load;
00053 u_pwd_close_cb_t cb_close;
00054
00055 u_pwd_notify_cb_t cb_notify;
00056
00057
00058 time_t last_mod;
00059 int in_memory;
00060 u_hmap_t *db;
00061 };
00062
00063
00064
00065 struct u_pwd_rec_s
00066 {
00067 char *user;
00068 char *pass;
00069 char *opaque;
00070 };
00071
00161 int u_pwd_init (const char *res_uri, u_pwd_open_cb_t cb_open,
00162 u_pwd_load_cb_t cb_load, u_pwd_close_cb_t cb_close,
00163 u_pwd_notify_cb_t cb_notify, u_pwd_hash_cb_t cb_hash,
00164 size_t hash_len, int in_memory, u_pwd_t **ppwd)
00165 {
00166 u_pwd_t *pwd;
00167
00168 dbg_return_if (res_uri == NULL, ~0);
00169 dbg_return_if (cb_open == NULL, ~0);
00170 dbg_return_if (cb_load == NULL, ~0);
00171
00172
00173 dbg_return_if (cb_hash && !hash_len, ~0);
00174 dbg_return_if (ppwd == NULL, ~0);
00175
00176
00177 pwd = u_zalloc(sizeof(u_pwd_t));
00178 dbg_err_sif (pwd == NULL);
00179
00180
00181 pwd->res_handler = NULL;
00182 dbg_err_if (u_strlcpy(pwd->res_uri, res_uri, sizeof pwd->res_uri));
00183
00184 pwd->hash_len = hash_len;
00185 pwd->cb_hash = cb_hash;
00186 pwd->cb_open = cb_open;
00187 pwd->cb_load = cb_load;
00188 pwd->cb_close = cb_close;
00189 pwd->cb_notify = cb_notify;
00190 pwd->last_mod = 0;
00191 pwd->in_memory = in_memory;
00192 pwd->db = NULL;
00193
00194
00195
00196
00197 *ppwd = pwd;
00198
00199 return 0;
00200 err:
00201 u_pwd_term(pwd);
00202 return ~0;
00203 }
00204
00219 int u_pwd_retr (u_pwd_t *pwd, const char *user, u_pwd_rec_t **prec)
00220 {
00221 dbg_return_if (pwd == NULL, ~0);
00222 dbg_return_if (user == NULL, ~0);
00223 dbg_return_if (prec == NULL, ~0);
00224
00225
00226
00227 if (pwd->in_memory)
00228 return u_pwd_retr_mem(pwd, user, prec);
00229
00230 return u_pwd_retr_res(pwd, user, prec);
00231 }
00232
00246 int u_pwd_auth_user (u_pwd_t *pwd, const char *user, const char *password)
00247 {
00248 int rc;
00249 u_pwd_rec_t *rec = NULL;
00250 char *__p = NULL, __pstack[U_PWD_LINE_MAX];
00251
00252 dbg_return_if (password == NULL, ~0);
00253
00254
00255 dbg_err_if (u_pwd_retr(pwd, user, &rec));
00256
00257
00258 if (pwd->cb_hash)
00259 {
00260
00261 dbg_err_if ((__p = u_zalloc(pwd->hash_len)) == NULL);
00262 (void) pwd->cb_hash(password, strlen(password), __p);
00263 }
00264 else
00265 {
00266 (void) u_strlcpy(__pstack, password, sizeof __pstack);
00267 __p = __pstack;
00268 }
00269
00270 rc = strcmp(__p, rec->pass);
00271
00272
00273 if (__p && (__p != __pstack))
00274 u_free(__p);
00275
00276
00277 if (!pwd->in_memory)
00278 u_pwd_rec_free(pwd, rec);
00279
00280 return rc;
00281 err:
00282 if (__p && (__p != __pstack))
00283 u_free(__p);
00284
00285 if (!pwd->in_memory && rec)
00286 u_pwd_rec_free(pwd, rec);
00287
00288 return ~0;
00289 }
00290
00300 void u_pwd_term (u_pwd_t *pwd)
00301 {
00302 nop_return_if (pwd == NULL, );
00303
00304 (void) u_pwd_db_term(pwd);
00305
00306 U_FREE(pwd);
00307
00308 return;
00309 }
00310
00327 int u_pwd_init_file (const char *res_uri, u_pwd_hash_cb_t cb_hash,
00328 size_t hash_len, int in_memory, u_pwd_t **ppwd)
00329 {
00330 return u_pwd_init (res_uri, __file_open, __file_load, __file_close,
00331 __file_notify, cb_hash, hash_len, in_memory, ppwd);
00332 }
00333
00346 void u_pwd_rec_free (u_pwd_t *pwd, u_pwd_rec_t *rec)
00347 {
00348 dbg_return_if (pwd == NULL, );
00349 dbg_return_if (rec == NULL, );
00350
00351 U_FREE(rec->user);
00352 U_FREE(rec->pass);
00353 U_FREE(rec->opaque);
00354
00355 u_free(rec);
00356
00357 return;
00358 }
00359
00370 const char *u_pwd_rec_get_user (u_pwd_rec_t *rec)
00371 {
00372 dbg_return_if (rec == NULL, NULL);
00373 return rec->user;
00374 }
00375
00386 const char *u_pwd_rec_get_password (u_pwd_rec_t *rec)
00387 {
00388 dbg_return_if (rec == NULL, NULL);
00389 return rec->pass;
00390 }
00391
00401 const char *u_pwd_rec_get_opaque (u_pwd_rec_t *rec)
00402 {
00403 dbg_return_if (rec == NULL, NULL);
00404 return rec->opaque;
00405 }
00406
00417 int u_pwd_in_memory (u_pwd_t *pwd)
00418 {
00419 return pwd->in_memory;
00420 }
00421
00426 static int u_pwd_load (u_pwd_t *pwd)
00427 {
00428 dbg_return_if (pwd == NULL, ~0);
00429 dbg_return_if (!pwd->in_memory, ~0);
00430
00431
00432 if (pwd->db)
00433 (void) u_pwd_db_term(pwd);
00434
00435
00436 dbg_err_if (u_pwd_db_new(pwd));
00437 dbg_err_if (u_pwd_db_load(pwd));
00438
00439 return 0;
00440 err:
00441 return ~0;
00442 }
00443
00444 static int u_pwd_retr_res (u_pwd_t *pwd, const char *user,
00445 u_pwd_rec_t **prec)
00446 {
00447 size_t lc, got_it = 0, ntoks;
00448 char ln[U_PWD_LINE_MAX], uu[U_PWD_LINE_MAX];
00449 char **toks = NULL;
00450 u_pwd_rec_t *rec = NULL;
00451
00452 dbg_return_if (pwd->res_uri == NULL, ~0);
00453 dbg_return_if (pwd->cb_load == NULL, ~0);
00454
00455
00456
00457 dbg_err_if (u_pwd_res_open(pwd));
00458
00459
00460 u_snprintf(uu, sizeof uu, "%s:", user);
00461
00462
00463 for (lc = 1; pwd->cb_load(ln, sizeof ln, pwd->res_handler) != NULL; lc++)
00464 {
00465
00466 if (ln[0] == '#')
00467 continue;
00468
00469
00470
00471
00472
00473 if (strstr(ln, uu) == ln)
00474 {
00475 got_it = 1;
00476 break;
00477 }
00478 }
00479
00480
00481 dbg_err_ifm (!got_it, "user %s not found", user);
00482
00483
00484 if (ln[strlen(ln) - 1] == '\n')
00485 ln[strlen(ln) - 1] = '\0';
00486
00487
00488 dbg_err_ifm (u_strtok(ln, ":", &toks, &ntoks) || ntoks < 2,
00489 "bad syntax at line %zu (%s)", lc, ln);
00490
00491
00492 dbg_err_if (u_pwd_rec_new(toks[0], toks[1], ntoks < 3 ? NULL : toks[2],
00493 &rec));
00494
00495
00496 u_strtok_cleanup(toks, ntoks);
00497
00498
00499 u_pwd_res_close(pwd);
00500
00501
00502 *prec = rec;
00503
00504 return 0;
00505 err:
00506 if (rec)
00507 u_pwd_rec_free(pwd, rec);
00508
00509 if (toks)
00510 u_strtok_cleanup(toks, ntoks);
00511
00512 u_pwd_res_close(pwd);
00513
00514 return ~0;
00515 }
00516
00517 static int u_pwd_res_open (u_pwd_t *pwd)
00518 {
00519 dbg_return_if (pwd->cb_open == NULL, ~0);
00520
00521 if (pwd->res_handler != NULL)
00522 u_warn("non-NULL resource handler will be lost");
00523
00524 pwd->res_handler = NULL;
00525
00526 return pwd->cb_open(pwd->res_uri, &pwd->res_handler);
00527 }
00528
00529 static void u_pwd_res_close (u_pwd_t *pwd)
00530 {
00531 nop_return_if (pwd->res_handler == NULL, );
00532 nop_return_if (pwd->cb_close == NULL, );
00533
00534 pwd->cb_close(pwd->res_handler);
00535 pwd->res_handler = NULL;
00536
00537 return;
00538 }
00539
00540 static int u_pwd_rec_new (const char *user, const char *pass,
00541 const char *opaque, u_pwd_rec_t **prec)
00542 {
00543 u_pwd_rec_t *rec = NULL;
00544
00545 dbg_return_if (user == NULL, ~0);
00546 dbg_return_if (pass == NULL, ~0);
00547 dbg_return_if (prec == NULL, ~0);
00548
00549 rec = u_zalloc(sizeof(u_pwd_rec_t));
00550 dbg_err_sif (rec == NULL);
00551
00552 rec->user = u_strdup(user);
00553 dbg_err_sif (rec->user == NULL);
00554
00555 rec->pass = u_strdup(pass);
00556 dbg_err_sif (rec->pass == NULL);
00557
00558
00559 if (opaque)
00560 {
00561 rec->opaque = u_strdup(opaque);
00562 dbg_err_sif (rec->opaque == NULL);
00563 }
00564
00565 *prec = rec;
00566
00567 return 0;
00568 err:
00569 if (rec)
00570 {
00571 U_FREE(rec->user);
00572 U_FREE(rec->pass);
00573 U_FREE(rec->opaque);
00574 u_free(rec);
00575 }
00576 return ~0;
00577 }
00578
00579 static int u_pwd_retr_mem (u_pwd_t *pwd, const char *user,
00580 u_pwd_rec_t **prec)
00581 {
00582 u_pwd_rec_t *pr = NULL;
00583
00584 dbg_return_if (pwd == NULL, ~0);
00585 dbg_return_if (user == NULL, ~0);
00586 dbg_return_if (prec == NULL, ~0);
00587
00588
00589 dbg_ifb (u_pwd_need_reload(pwd))
00590 u_warn("error reloading master pwd file: using stale cache");
00591
00592 dbg_err_if (pwd->db == NULL);
00593
00594 pr = (u_pwd_rec_t *) u_hmap_easy_get(pwd->db, user);
00595 dbg_err_if (pr == NULL);
00596
00597 *prec = pr;
00598
00599 return 0;
00600 err:
00601 return ~0;
00602 }
00603
00604 static int u_pwd_need_reload (u_pwd_t *pwd)
00605 {
00606 time_t update_timestamp;
00607
00608
00609 nop_return_if (!pwd->in_memory, 0);
00610 nop_return_if (pwd->cb_notify == NULL, 0);
00611
00612
00613 if (!pwd->cb_notify(pwd->res_uri, pwd->last_mod, &update_timestamp))
00614 return 0;
00615
00616
00617 pwd->last_mod = update_timestamp;
00618
00619
00620 return u_pwd_load(pwd);
00621 }
00622
00623 static int u_pwd_db_new (u_pwd_t *pwd)
00624 {
00625 u_hmap_opts_t *hopts = NULL;
00626
00627 dbg_err_if (pwd == NULL);
00628
00629 dbg_err_if (u_hmap_opts_new(&hopts));
00630 dbg_err_if (u_hmap_opts_set_val_freefunc(hopts, &__hmap_pwd_rec_free));
00631
00632 return u_hmap_easy_new(hopts, &pwd->db);
00633 err:
00634 if (hopts)
00635 u_hmap_opts_free(hopts);
00636 return ~0;
00637 }
00638
00639 static int u_pwd_db_term (u_pwd_t *pwd)
00640 {
00641 dbg_return_if (pwd == NULL, ~0);
00642
00643 nop_return_if (pwd->db == NULL, 0);
00644
00645 u_hmap_easy_free(pwd->db);
00646 pwd->db = NULL;
00647
00648 return 0;
00649 }
00650
00651 static int u_pwd_db_load (u_pwd_t *pwd)
00652 {
00653 size_t lc, ntoks;
00654 char ln[U_PWD_LINE_MAX];
00655 char **toks = NULL;
00656 u_pwd_rec_t *rec = NULL;
00657
00658 dbg_return_if (pwd->res_uri == NULL, ~0);
00659 dbg_return_if (pwd->cb_load == NULL, ~0);
00660
00661
00662
00663 dbg_err_if (u_pwd_res_open(pwd));
00664
00665 for (lc = 1; pwd->cb_load(ln, sizeof ln, pwd->res_handler) != NULL; lc++)
00666 {
00667
00668 if (toks)
00669 {
00670 u_strtok_cleanup(toks, ntoks);
00671 toks = NULL;
00672 }
00673
00674
00675 if (ln[0] == '#')
00676 continue;
00677
00678
00679 if (ln[strlen(ln) - 1] == '\n')
00680 ln[strlen(ln) - 1] = '\0';
00681
00682
00683 dbg_ifb (u_strtok(ln, ":", &toks, &ntoks) || ntoks < 2)
00684 {
00685 u_info("bad syntax at line %zu (%s)", lc, ln);
00686 continue;
00687 }
00688
00689
00690 dbg_ifb (u_pwd_rec_new(toks[0], toks[1], ntoks < 3 ? NULL : toks[2],
00691 &rec))
00692 {
00693 u_info("could not create record for entry at line %zu", lc);
00694 continue;
00695 }
00696
00697
00698 dbg_ifb (u_pwd_db_push(pwd, rec))
00699 {
00700 u_info("could not push record for entry at line %zu", lc);
00701 u_pwd_rec_free(pwd, rec), rec = NULL;
00702 }
00703
00704 rec = NULL;
00705 }
00706
00707 if (toks)
00708 u_strtok_cleanup(toks, ntoks);
00709
00710 if (rec)
00711 u_pwd_rec_free(pwd, rec);
00712
00713 u_pwd_res_close(pwd);
00714
00715 return 0;
00716 err:
00717 if (rec)
00718 u_pwd_rec_free(pwd, rec);
00719
00720 if (toks)
00721 u_strtok_cleanup(toks, ntoks);
00722
00723 u_pwd_res_close(pwd);
00724
00725 return ~0;
00726 }
00727
00728 static int u_pwd_db_push (u_pwd_t *pwd, u_pwd_rec_t *rec)
00729 {
00730 dbg_return_if (pwd->db == NULL, ~0);
00731 dbg_return_if (rec == NULL, ~0);
00732 dbg_return_if (rec->user == NULL, ~0);
00733
00734 return u_hmap_easy_put(pwd->db, rec->user, (const void *) rec);
00735 }
00736
00737
00738
00739
00740 static int __file_open (const char *path, void **pfp)
00741 {
00742 FILE *fp = NULL;
00743
00744 dbg_err_sif ((fp = fopen(path, "r")) == NULL);
00745
00746 *pfp = (void *) fp;
00747
00748 return 0;
00749 err:
00750 return ~0;
00751 }
00752
00753 static void __file_close (void *fp)
00754 {
00755 dbg_return_sif (fclose((FILE *) fp), );
00756 return;
00757 }
00758
00759 static char *__file_load (char *str, int size, void *fp)
00760 {
00761 return fgets(str, size, (FILE *) fp);
00762 }
00763
00764
00765 static int __file_notify (const char *path, time_t last_update,
00766 time_t *pnew_update)
00767 {
00768 struct stat sb;
00769
00770 dbg_err_if (path == NULL);
00771
00772 dbg_err_sif (stat(path, &sb));
00773
00774 if (sb.st_ctime != last_update)
00775 {
00776 *pnew_update = sb.st_ctime;
00777 return 1;
00778 }
00779
00780
00781 err:
00782 return 0;
00783 }
00784
00785
00786 static void __hmap_pwd_rec_free (void *val)
00787 {
00788 u_pwd_t fake_pwd;
00789
00790 fake_pwd.in_memory = 1;
00791
00792 u_pwd_rec_free(&fake_pwd, (u_pwd_rec_t *) val);
00793
00794 return;
00795 }