00001
00002
00003
00004
00005 static const char rcsid[] =
00006 "$Id: pwd.c,v 1.10 2008/04/02 10:30:43 tho Exp $";
00007
00008 #include <sys/stat.h>
00009 #include <sys/types.h>
00010 #include <u/libu_conf.h>
00011 #include <u/libu.h>
00012 #include <toolbox/hmap.h>
00013 #include <toolbox/pwd.h>
00014
00015
00016 static int u_pwd_db_new (u_pwd_t *pwd);
00017 static int u_pwd_db_term (u_pwd_t *pwd);
00018 static int u_pwd_db_load (u_pwd_t *pwd);
00019 static int u_pwd_db_push (u_pwd_t *pwd, u_pwd_rec_t *rec);
00020 static void __hmap_pwd_rec_free (u_hmap_o_t *obj);
00021
00022
00023 static int u_pwd_load (u_pwd_t *pwd);
00024 static int u_pwd_need_reload (u_pwd_t *pwd);
00025
00026
00027 static int u_pwd_rec_new (const char *user, const char *pass,
00028 const char *opaque, u_pwd_rec_t **prec);
00029 static int u_pwd_retr_mem (u_pwd_t *pwd, const char *user,
00030 u_pwd_rec_t **prec);
00031 static int u_pwd_retr_res (u_pwd_t *pwd, const char *user,
00032 u_pwd_rec_t **prec);
00033
00034
00035 static int u_pwd_res_open (u_pwd_t *pwd);
00036 static void u_pwd_res_close (u_pwd_t *pwd);
00037
00038
00039 static int __file_open (const char *path, void **pfp);
00040 static void __file_close (void *fp);
00041 static char *__file_load (char *str, int size, void *fp);
00042 static int __file_notify (const char *path, time_t last_update,
00043 time_t *pnew_update);
00044
00045
00046 struct u_pwd_s
00047 {
00048 void *res_handler;
00049 char res_uri[U_FILENAME_MAX + 1];
00050
00051 size_t hash_len;
00052 u_pwd_hash_cb_t cb_hash;
00053
00054 u_pwd_open_cb_t cb_open;
00055 u_pwd_load_cb_t cb_load;
00056 u_pwd_close_cb_t cb_close;
00057
00058 u_pwd_notify_cb_t cb_notify;
00059
00060
00061 time_t last_mod;
00062 int in_memory;
00063 u_hmap_t *db;
00064 };
00065
00066
00067
00068 struct u_pwd_rec_s
00069 {
00070 char *user;
00071 char *pass;
00072 char *opaque;
00073 };
00074
00098 int u_pwd_init (const char *res_uri, u_pwd_open_cb_t cb_open,
00099 u_pwd_load_cb_t cb_load, u_pwd_close_cb_t cb_close,
00100 u_pwd_notify_cb_t cb_notify, u_pwd_hash_cb_t cb_hash,
00101 size_t hash_len, int in_memory, u_pwd_t **ppwd)
00102 {
00103 u_pwd_t *pwd;
00104
00105 dbg_return_if (res_uri == NULL, ~0);
00106 dbg_return_if (cb_open == NULL, ~0);
00107 dbg_return_if (cb_load == NULL, ~0);
00108
00109
00110 dbg_return_if (cb_hash && !hash_len, ~0);
00111 dbg_return_if (ppwd == NULL, ~0);
00112
00113
00114 pwd = u_zalloc(sizeof(u_pwd_t));
00115 dbg_err_sif (pwd == NULL);
00116
00117
00118 pwd->res_handler = NULL;
00119 strlcpy(pwd->res_uri, res_uri, sizeof pwd->res_uri);
00120
00121 pwd->hash_len = hash_len;
00122 pwd->cb_hash = cb_hash;
00123 pwd->cb_open = cb_open;
00124 pwd->cb_load = cb_load;
00125 pwd->cb_close = cb_close;
00126 pwd->cb_notify = cb_notify;
00127 pwd->last_mod = 0;
00128 pwd->in_memory = in_memory;
00129 pwd->db = NULL;
00130
00131
00132
00133
00134 *ppwd = pwd;
00135
00136 return 0;
00137 err:
00138 u_pwd_term(pwd);
00139 return ~0;
00140 }
00141
00152 int u_pwd_retr (u_pwd_t *pwd, const char *user, u_pwd_rec_t **prec)
00153 {
00154 dbg_return_if (pwd == NULL, ~0);
00155 dbg_return_if (user == NULL, ~0);
00156 dbg_return_if (prec == NULL, ~0);
00157
00158
00159
00160 if (pwd->in_memory)
00161 return u_pwd_retr_mem(pwd, user, prec);
00162
00163 return u_pwd_retr_res(pwd, user, prec);
00164 }
00165
00175 int u_pwd_auth_user (u_pwd_t *pwd, const char *user, const char *password)
00176 {
00177 int rc;
00178 u_pwd_rec_t *rec = NULL;
00179 char *__p = NULL, __pstack[U_PWD_LINE_MAX];
00180
00181
00182 dbg_err_if (u_pwd_retr(pwd, user, &rec));
00183
00184
00185 if (pwd->cb_hash)
00186 {
00187
00188 dbg_err_if ((__p = u_zalloc(pwd->hash_len)) == NULL);
00189 (void) pwd->cb_hash(password, strlen(password), __p);
00190 }
00191 else
00192 {
00193 (void) strlcpy(__pstack, password, sizeof __pstack);
00194 __p = __pstack;
00195 }
00196
00197 rc = strcmp(__p, rec->pass);
00198
00199
00200 if (__p && (__p != __pstack))
00201 u_free(__p);
00202
00203
00204 if (!pwd->in_memory)
00205 u_pwd_rec_free(pwd, rec);
00206
00207 return rc;
00208 err:
00209 if (__p && (__p != __pstack))
00210 u_free(__p);
00211
00212 if (!pwd->in_memory && rec)
00213 u_pwd_rec_free(pwd, rec);
00214
00215 return ~0;
00216 }
00217
00225 void u_pwd_term (u_pwd_t *pwd)
00226 {
00227 nop_return_if (pwd == NULL, );
00228
00229 (void) u_pwd_db_term(pwd);
00230
00231 U_FREE(pwd);
00232
00233 return;
00234 }
00235
00249 int u_pwd_init_file (const char *res_uri, u_pwd_hash_cb_t cb_hash,
00250 size_t hash_len, int in_memory, u_pwd_t **ppwd)
00251 {
00252 return u_pwd_init (res_uri, __file_open, __file_load, __file_close,
00253 __file_notify, cb_hash, hash_len, in_memory, ppwd);
00254 }
00255
00265 void u_pwd_rec_free (u_pwd_t *pwd, u_pwd_rec_t *rec)
00266 {
00267 dbg_return_if (pwd == NULL, );
00268 dbg_return_if (rec == NULL, );
00269
00270
00271 nop_return_if (pwd->in_memory, );
00272
00273 U_FREE(rec->user);
00274 U_FREE(rec->pass);
00275 U_FREE(rec->opaque);
00276
00277 u_free(rec);
00278
00279 return;
00280 }
00281
00289 const char *u_pwd_rec_get_user (u_pwd_rec_t *rec)
00290 {
00291 dbg_return_if (rec == NULL, NULL);
00292 return rec->user;
00293 }
00294
00302 const char *u_pwd_rec_get_password (u_pwd_rec_t *rec)
00303 {
00304 dbg_return_if (rec == NULL, NULL);
00305 return rec->pass;
00306 }
00307
00315 const char *u_pwd_rec_get_opaque (u_pwd_rec_t *rec)
00316 {
00317 dbg_return_if (rec == NULL, NULL);
00318 return rec->opaque;
00319 }
00320
00328 int u_pwd_in_memory (u_pwd_t *pwd)
00329 {
00330 return pwd->in_memory;
00331 }
00332
00337 static int u_pwd_load (u_pwd_t *pwd)
00338 {
00339 dbg_return_if (pwd == NULL, ~0);
00340 dbg_return_if (!pwd->in_memory, ~0);
00341
00342
00343 if (pwd->db)
00344 (void) u_pwd_db_term(pwd);
00345
00346
00347 dbg_err_if (u_pwd_db_new(pwd));
00348 dbg_err_if (u_pwd_db_load(pwd));
00349
00350 return 0;
00351 err:
00352 return ~0;
00353 }
00354
00355 static int u_pwd_retr_res (u_pwd_t *pwd, const char *user,
00356 u_pwd_rec_t **prec)
00357 {
00358 size_t lc, got_it = 0;
00359 char ln[U_PWD_LINE_MAX], __user[U_PWD_LINE_MAX];
00360 char *toks[3 + 1];
00361 u_pwd_rec_t *rec = NULL;
00362
00363 dbg_return_if (pwd->res_uri == NULL, ~0);
00364 dbg_return_if (pwd->cb_load == NULL, ~0);
00365
00366
00367
00368 dbg_err_if (u_pwd_res_open(pwd));
00369
00370
00371 u_snprintf(__user, sizeof __user, "%s:", user);
00372
00373
00374 for (lc = 1; pwd->cb_load(ln, sizeof ln, pwd->res_handler) != NULL; lc++)
00375 {
00376
00377 if (ln[0] == '#')
00378 continue;
00379
00380
00381
00382
00383
00384 if (strstr(ln, __user) == ln)
00385 {
00386 got_it = 1;
00387 break;
00388 }
00389 }
00390
00391
00392 dbg_err_ifm (!got_it, "user %s not found", user);
00393
00394
00395 if (ln[strlen(ln) - 1] == '\n')
00396 ln[strlen(ln) - 1] = '\0';
00397
00398
00399 dbg_err_ifm (u_tokenize(ln, ":", toks, 3),
00400 "bad syntax at line %zu (%s)", lc, ln);
00401
00402
00403 dbg_err_if (u_pwd_rec_new(toks[0], toks[1], toks[2], &rec));
00404
00405
00406 u_pwd_res_close(pwd);
00407
00408
00409 *prec = rec;
00410
00411 return 0;
00412 err:
00413 if (rec)
00414 u_pwd_rec_free(pwd, rec);
00415
00416 u_pwd_res_close(pwd);
00417
00418 return ~0;
00419 }
00420
00421 static int u_pwd_res_open (u_pwd_t *pwd)
00422 {
00423 dbg_return_if (pwd->cb_open == NULL, ~0);
00424
00425 if (pwd->res_handler != NULL)
00426 warn("non-NULL resource handler will be lost");
00427
00428 pwd->res_handler = NULL;
00429
00430 return pwd->cb_open(pwd->res_uri, &pwd->res_handler);
00431 }
00432
00433 static void u_pwd_res_close (u_pwd_t *pwd)
00434 {
00435 nop_return_if (pwd->res_handler == NULL, );
00436 nop_return_if (pwd->cb_close == NULL, );
00437
00438 pwd->cb_close(pwd->res_handler);
00439 pwd->res_handler = NULL;
00440
00441 return;
00442 }
00443
00444 static int u_pwd_rec_new (const char *user, const char *pass,
00445 const char *opaque, u_pwd_rec_t **prec)
00446 {
00447 u_pwd_rec_t *rec = NULL;
00448
00449 dbg_return_if (user == NULL, ~0);
00450 dbg_return_if (pass == NULL, ~0);
00451 dbg_return_if (prec == NULL, ~0);
00452
00453 rec = u_zalloc(sizeof(u_pwd_rec_t));
00454 dbg_err_sif (rec == NULL);
00455
00456 rec->user = u_strdup(user);
00457 dbg_err_sif (rec->user == NULL);
00458
00459 rec->pass = u_strdup(pass);
00460 dbg_err_sif (rec->pass == NULL);
00461
00462
00463 if (opaque)
00464 {
00465 rec->opaque = u_strdup(opaque);
00466 dbg_err_sif (rec->opaque == NULL);
00467 }
00468
00469 *prec = rec;
00470
00471 return 0;
00472 err:
00473 if (rec)
00474 {
00475 U_FREE(rec->user);
00476 U_FREE(rec->pass);
00477 U_FREE(rec->opaque);
00478 u_free(rec);
00479 }
00480 return ~0;
00481 }
00482
00483 static int u_pwd_retr_mem (u_pwd_t *pwd, const char *user,
00484 u_pwd_rec_t **prec)
00485 {
00486 u_hmap_o_t *hobj = NULL;
00487
00488 dbg_return_if (pwd == NULL, ~0);
00489 dbg_return_if (user == NULL, ~0);
00490 dbg_return_if (prec == NULL, ~0);
00491
00492
00493 dbg_ifb (u_pwd_need_reload(pwd))
00494 warn("error reloading master pwd file: using stale cache");
00495
00496 dbg_err_if (pwd->db == NULL);
00497 dbg_err_if (u_hmap_get(pwd->db, user, &hobj));
00498 *prec = (u_pwd_rec_t *) hobj->val;
00499
00500 return 0;
00501 err:
00502 return ~0;
00503 }
00504
00505 static int u_pwd_need_reload (u_pwd_t *pwd)
00506 {
00507 time_t update_timestamp;
00508
00509
00510 nop_return_if (!pwd->in_memory, 0);
00511 nop_return_if (pwd->cb_notify == NULL, 0);
00512
00513
00514 if (!pwd->cb_notify(pwd->res_uri, pwd->last_mod, &update_timestamp))
00515 return 0;
00516
00517
00518 pwd->last_mod = update_timestamp;
00519
00520
00521 return u_pwd_load(pwd);
00522 }
00523
00524 static int u_pwd_db_new (u_pwd_t *pwd)
00525 {
00526 u_hmap_opts_t hopts;
00527
00528 dbg_return_if (pwd == NULL, ~0);
00529
00530 u_hmap_opts_init(&hopts);
00531 hopts.options |= U_HMAP_OPTS_OWNSDATA;
00532 hopts.f_free = __hmap_pwd_rec_free;
00533
00534 return u_hmap_new(&hopts, &pwd->db);
00535 }
00536
00537 static int u_pwd_db_term (u_pwd_t *pwd)
00538 {
00539 dbg_return_if (pwd == NULL, ~0);
00540
00541 nop_return_if (pwd->db == NULL, 0);
00542
00543 u_hmap_free(pwd->db);
00544 pwd->db = NULL;
00545
00546 return 0;
00547 }
00548
00549 static int u_pwd_db_load (u_pwd_t *pwd)
00550 {
00551 size_t lc;
00552 char ln[U_PWD_LINE_MAX];
00553 char *toks[3 + 1];
00554 u_pwd_rec_t *rec = NULL;
00555
00556 dbg_return_if (pwd->res_uri == NULL, ~0);
00557 dbg_return_if (pwd->cb_load == NULL, ~0);
00558
00559
00560
00561 dbg_err_if (u_pwd_res_open(pwd));
00562
00563 for (lc = 1; pwd->cb_load(ln, sizeof ln, pwd->res_handler) != NULL; lc++)
00564 {
00565
00566 if (ln[0] == '#')
00567 continue;
00568
00569
00570 if (ln[strlen(ln) - 1] == '\n')
00571 ln[strlen(ln) - 1] = '\0';
00572
00573
00574 dbg_ifb (u_tokenize(ln, ":", toks, 3))
00575 {
00576 info("bad syntax at line %zu (%s)", lc, ln);
00577 continue;
00578 }
00579
00580
00581 dbg_ifb (u_pwd_rec_new(toks[0], toks[1], toks[2], &rec))
00582 {
00583 info("could not create record for entry at line %zu", lc);
00584 continue;
00585 }
00586
00587
00588 dbg_ifb (u_pwd_db_push(pwd, rec))
00589 {
00590 info("could not push record for entry at line %zu", lc);
00591 u_pwd_rec_free(pwd, rec), rec = NULL;
00592 }
00593
00594 rec = NULL;
00595 }
00596
00597 if (rec)
00598 u_pwd_rec_free(pwd, rec);
00599
00600 u_pwd_res_close(pwd);
00601
00602 return 0;
00603 err:
00604 if (rec)
00605 u_pwd_rec_free(pwd, rec);
00606
00607 u_pwd_res_close(pwd);
00608
00609 return ~0;
00610 }
00611
00612 static int u_pwd_db_push (u_pwd_t *pwd, u_pwd_rec_t *rec)
00613 {
00614 char *hkey = NULL;
00615 u_hmap_o_t *hobj = NULL;
00616
00617 dbg_return_if (pwd->db == NULL, ~0);
00618 dbg_return_if (rec == NULL, ~0);
00619 dbg_return_if (rec->user == NULL, ~0);
00620
00621 hkey = u_strdup(rec->user);
00622 dbg_err_if (hkey == NULL);
00623
00624 hobj = u_hmap_o_new((void *) hkey, (void *) rec);
00625 dbg_err_if (hobj == NULL);
00626
00627 return u_hmap_put(pwd->db, hobj, NULL);
00628 err:
00629 if (hkey)
00630 u_free(hkey);
00631 if (hobj)
00632 u_hmap_o_free(hobj);
00633 return ~0;
00634 }
00635
00636
00637
00638
00639 static int __file_open (const char *path, void **pfp)
00640 {
00641 FILE *fp = NULL;
00642
00643 dbg_err_sif ((fp = fopen(path, "r")) == NULL);
00644
00645 *pfp = (void *) fp;
00646
00647 return 0;
00648 err:
00649 return ~0;
00650 }
00651
00652 static void __file_close (void *fp)
00653 {
00654 dbg_return_sif (fclose((FILE *) fp), );
00655 return;
00656 }
00657
00658 static char *__file_load (char *str, int size, void *fp)
00659 {
00660 return fgets(str, size, (FILE *) fp);
00661 }
00662
00663
00664 static int __file_notify (const char *path, time_t last_update,
00665 time_t *pnew_update)
00666 {
00667 struct stat sb;
00668
00669 dbg_err_if (path == NULL);
00670
00671 dbg_err_sif (stat(path, &sb));
00672
00673 if (sb.st_ctime != last_update)
00674 {
00675 *pnew_update = sb.st_ctime;
00676 return 1;
00677 }
00678
00679
00680 err:
00681 return 0;
00682 }
00683
00684
00685 static void __hmap_pwd_rec_free (u_hmap_o_t *obj)
00686 {
00687 u_pwd_t fake_pwd;
00688
00689 fake_pwd.in_memory = 1;
00690
00691 U_FREE(obj->key);
00692 u_pwd_rec_free(&fake_pwd, (u_pwd_rec_t *) obj->val);
00693
00694 return;
00695 }