static int pw_update(struct passwd * pwd, char const * user) { struct passwd *pw = NULL; struct passwd *old_pw = NULL; int rc, pfd, tfd; if ((rc = pwdb_check()) != 0) return (rc); if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(conf.etcpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); close(tfd); err(1, "pw_copy()"); } fsync(tfd); close(tfd); /* * in case of deletion of a user, the whole database * needs to be regenerated */ if (pw_mkdb(pw != NULL ? pw->pw_name : NULL) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); return (0); }
static void chap_send_failure(struct chap_auth_data_t *ad) { struct chap_failure_t msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_FAILURE, .hdr.id = ad->id, .hdr.len = htons(sizeof(msg) - 1 - 2), .message = MSG_FAILURE, }; if (conf_ppp_verbose) log_ppp_info2("send [CHAP Failure id=%x \"%s\"]\n", msg.hdr.id, MSG_FAILURE); ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); } static void chap_send_success(struct chap_auth_data_t *ad) { struct chap_success_t msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_SUCCESS, .hdr.id = ad->id, .hdr.len = htons(sizeof(msg)-1-2), .message = MSG_SUCCESS, }; if (conf_ppp_verbose) log_ppp_info2("send [CHAP Success id=%x \"%s\"]\n", msg.hdr.id, MSG_SUCCESS); ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); } static void chap_send_challenge(struct chap_auth_data_t *ad) { struct chap_challenge_t msg = { .hdr.proto = htons(PPP_CHAP), .hdr.code = CHAP_CHALLENGE, .hdr.id = ++ad->id, .hdr.len = htons(sizeof(msg) - 2), .val_size = VALUE_SIZE, }; read(urandom_fd, ad->val, VALUE_SIZE); memcpy(msg.val, ad->val, VALUE_SIZE); if (conf_ppp_verbose) { log_ppp_info2("send [CHAP Challenge id=%x <", msg.hdr.id); print_buf(msg.val, VALUE_SIZE); log_ppp_info2(">]\n"); } ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2); if (conf_timeout && !ad->timeout.tpd) triton_timer_add(ad->ppp->ctrl->ctx, &ad->timeout, 0); } static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr) { MD5_CTX md5_ctx; uint8_t md5[MD5_DIGEST_LENGTH]; char *passwd; char *name; int r; struct chap_challenge_t *msg = (struct chap_challenge_t*)hdr; if (ad->timeout.tpd) triton_timer_del(&ad->timeout); if (conf_ppp_verbose) { log_ppp_info2("recv [CHAP Response id=%x <", msg->hdr.id); print_buf(msg->val, msg->val_size); log_ppp_info2(">, name=\""); print_str(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2); log_ppp_info2("\"]\n"); } if (msg->hdr.id != ad->id) { if (conf_ppp_verbose) log_ppp_warn("chap-md5: id mismatch\n"); return; } if (msg->val_size != VALUE_SIZE) { log_ppp_error("chap-md5: incorrect value-size (%i)\n", msg->val_size); chap_send_failure(ad); if (ad->started) ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); else ppp_auth_failed(ad->ppp, NULL); return; } name = _strndup(msg->name,ntohs(msg->hdr.len) - sizeof(*msg) + 2); if (conf_any_login) { if (ppp_auth_successed(ad->ppp, name)) { chap_send_failure(ad); ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); _free(name); return; } chap_send_success(ad); ad->started = 1; return; } r = pwdb_check(ad->ppp, name, PPP_CHAP, CHAP_MD5, ad->id, ad->val, VALUE_SIZE, msg->val); if (r == PWDB_NO_IMPL) { passwd = pwdb_get_passwd(ad->ppp,name); if (!passwd) { _free(name); if (conf_ppp_verbose) log_ppp_warn("chap-md5: user not found\n"); chap_send_failure(ad); return; } MD5_Init(&md5_ctx); MD5_Update(&md5_ctx,&msg->hdr.id,1); MD5_Update(&md5_ctx,passwd,strlen(passwd)); MD5_Update(&md5_ctx,ad->val,VALUE_SIZE); MD5_Final(md5,&md5_ctx); if (memcmp(md5,msg->val,sizeof(md5))) { if (conf_ppp_verbose) log_ppp_warn("chap-md5: challenge response mismatch\n"); chap_send_failure(ad); if (ad->started) ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); else ppp_auth_failed(ad->ppp, name); _free(name); } else { if (!ad->started) { if (ppp_auth_successed(ad->ppp, name)) { chap_send_failure(ad); ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); _free(name); } else { chap_send_success(ad); ad->started = 1; if (conf_interval) triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); } } else _free(name); } _free(passwd); } else if (r == PWDB_DENIED) { chap_send_failure(ad); if (ad->started) ppp_terminate(ad->ppp, TERM_USER_ERROR, 0); else ppp_auth_failed(ad->ppp, name); _free(name); } else { if (!ad->started) { if (ppp_auth_successed(ad->ppp, name)) { chap_send_failure(ad); ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0); _free(name); } else { chap_send_success(ad); ad->started = 1; if (conf_interval) triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0); } } else { chap_send_success(ad); _free(name); } } } static int chap_check(uint8_t *ptr) { return *ptr == CHAP_MD5; } static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth) { struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth); chap_send_challenge(d); return 0; } static struct ppp_auth_handler_t chap= { .name = "CHAP-md5", .init = auth_data_init, .free = auth_data_free, .send_conf_req = lcp_send_conf_req, .recv_conf_req = lcp_recv_conf_req, .start = chap_start, .finish = chap_finish, .check = chap_check, .restart = chap_restart, }; static void chap_recv(struct ppp_handler_t *h) { struct chap_auth_data_t *d = container_of(h, typeof(*d), h); struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->buf; if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->buf_size - 2) { log_ppp_warn("chap-md5: short packet received\n"); return; } if (hdr->code == CHAP_RESPONSE) chap_recv_response(d, hdr); else log_ppp_warn("chap-md5: unknown code received %x\n", hdr->code); } static void load_config(void) { const char *opt; opt = conf_get_opt("auth", "timeout"); if (opt && atoi(opt) > 0) conf_timeout = atoi(opt); opt = conf_get_opt("auth", "interval"); if (opt && atoi(opt) > 0) conf_interval = atoi(opt); opt = conf_get_opt("auth", "max-failure"); if (opt && atoi(opt) > 0) conf_max_failure = atoi(opt); opt = conf_get_opt("auth", "any-login"); if (opt) conf_any_login = atoi(opt); } static void auth_chap_md5_init() { load_config(); if (ppp_auth_register_handler(&chap)) log_emerg("chap-md5: failed to register handler\n"); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); } DEFINE_INIT(4, auth_chap_md5_init);