📄 extens.c
字号:
* or clear out an entry... */static int update_db_record(int action, datum *content, radlast *rl,int month, int day){ void *data; int datasize; user_entry *tmp = (user_entry *)(content->dptr); port_entry *tpe; /* update fields */ tmp->day[month][day].on_line += rl->length; tmp->day[month][day].input_octets += rl->inb; tmp->day[month][day].output_octets += rl->outb; /* now it is time to check if this is a start or stop */ if (action == PW_STATUS_START) { tmp->day[month][day].nr_logins++; tmp->logins++; /* okay, start a new one ... */ datasize = content->dsize + sizeof(port_entry); data = (void *) malloc(datasize); if (data==NULL) { /* malloc error */ log_err("could not malloc for handling user acct\n"); content->dptr = NULL; return -1; } /* we have the required memory */ memcpy(data,content->dptr,content->dsize); /* paste the original data */ tpe = (port_entry *)((char *)data + content->dsize); /* store the new entry */ tpe->time = rl->ut_time; tpe->client_ip = rl->client_ip; tpe->port_type = rl->ent.port_type; tpe->port_number = rl->ent.port; tpe->nas_ip = rl->nas_ip; tpe->proto = rl->ent.proto; } else { /* this is a stop record */ int port_found = 0; /* now it is ugly ... */ datasize = sizeof(user_entry); /* do not attemp to take more */ data = (void *)malloc(content->dsize); /* make enough room */ if (data==NULL) { /* malloc error */ log_err("could not malloc for handling user acct\n"); content->dptr = NULL; return -1; } /* memory is okay */ if (content->dsize > sizeof(user_entry)) { /* do we have any port entry to rip off ? */ int ports_copied = 0; int nr_port_entry = 0; port_entry *dptr = (port_entry *)((char*)data+sizeof(user_entry)); /* go to first port entry */ tpe = (port_entry *)((char *)(content->dptr) + sizeof(user_entry)); /* be super-safe */ nr_port_entry = (content->dsize-sizeof(user_entry))/sizeof(port_entry); if (nr_port_entry*sizeof(port_entry)+sizeof(user_entry) != content->dsize) { /* somehow we've managed to break the port entries, we * don't have a valid number of entries */ log_err("ERROR: database is inconsistent for user '%s'." " Cleaned up.\n",rl->login); /* clean up the mess */ tmp->logins = 0; } else { /* we have a valid number of port entries, * now just in case tmp->logins have a different opinion ... */ if (tmp->logins != nr_port_entry) log_err("ERROR: database not okay for '%s': velived %d" "logins, have only %d\n", rl->login, tmp->logins, nr_port_entry); tmp->logins = nr_port_entry; } while (ports_copied < tmp->logins) { /* is this the port we are looking for ? */ if ((tpe->nas_ip!=rl->nas_ip) || (tpe->port_type != rl->ent.port_type) || (tpe->port_number != rl->ent.port) || port_found) { /* not our port */ memcpy((void *)dptr, (void *)tpe, sizeof(port_entry)); dptr++; datasize += sizeof(port_entry); } else /* port found */ port_found++; /* skip the current port */ tpe++; /* count any port as a copied one */ ports_copied++; } } if (port_found) tmp->logins--; /* all done */ memcpy(data, content->dptr, sizeof(user_entry)); /* paste orig. data */ } /* Now no matter what *data contains our data, with a size of datasize */ if ( content->dptr != NULL ) free(content->dptr); content->dsize = datasize; content->dptr = (char*)data; return 0;}/* * inserts a new entry for the username in the user_stats database */static int insert_db_record(int action,datum *content,radlast *rl,int month,int day){ user_entry *tmp; content->dsize = sizeof(user_entry); if (action == PW_STATUS_START) content->dsize += sizeof(port_entry); tmp = (user_entry *)malloc(content->dsize); if (tmp == NULL) { log_err("insert_db_record(): malloc error!\n"); content->dptr = NULL; return -2; } /* init things */ memset((char *)tmp, 0, sizeof(user_entry)); tmp->day[month][day].on_line += rl->length; tmp->day[month][day].input_octets += rl->inb; tmp->day[month][day].output_octets += rl->outb; if (action == PW_STATUS_START) { port_entry *tpe; tmp->logins = 1; tmp->day[month][day].nr_logins = 1; /* get the port_entry pointer */ tpe = (port_entry *)((char *)tmp + sizeof(user_entry)); tpe->time = rl->ut_time; tpe->client_ip = rl->client_ip; tpe->port_type = rl->ent.port_type; tpe->port_number = rl->ent.port; tpe->nas_ip = rl->nas_ip; tpe->proto = rl->ent.proto; } content->dptr = (char *)tmp; return 0;}/* * Updates the radlast logs... */extern int sockfd;extern int acctfd;static int update_radlast(radlast *rl){ pid_t child_pid; struct tm *time_info; { time_t crt_time = time(NULL); time_info = localtime(&crt_time); } /* fork a child to handle this job */ child_pid = fork(); if (child_pid < 0) { log_err("severe: Cannot fork() to writte radlast information\n"); return -1; } if (child_pid > 0) /* in the parent all is okay */ return 0; /* now in the child context do the lastlog update */ if (child_pid == 0) { FILE *fp; char log_file[PATH_MAX]; /* first close the acct and sock fd, we don't listen here */ close(acctfd); acctfd = -1; close(sockfd); sockfd = -1; memset(log_file, 0, sizeof(log_file)); snprintf(log_file, sizeof(log_file), "%s/%d/%s-%02d", radacct_dir, 1900+time_info->tm_year, RADIUS_LAST, time_info->tm_mon+1); /* extra safety never hurts */ umask(0027); /* now we should be safe */ if ((fp = fopen(log_file, "a")) != NULL) { if (fwrite(rl, sizeof(radlast), 1, fp) < 1) log_err("Could not write lastlog info for %s to %s\n", rl->login, log_file); else fclose(fp); } else log_err("Cannot open lastlog file '%s' for logging\n",log_file); exit(0); } return 0;}/* * * Function: update_user_status * * Given an acct packet, it updates the internal databse structure to be in * sync with the reality... * --cristiang */int update_user_status(AUTH_REQ *authreq){ GDBM_FILE dbf; int retval; datum key, content; int flag = GDBM_INSERT; char dbfile_name[PATH_MAX]; radlast rl; int action; struct tm *time_info; if (!authreq || !authreq->request) return -1; /* Now build the radlast packet ... */ action = build_radlast_from_authreq(&rl, authreq); if (!strlen(rl.login)) return -1; if ((action != PW_STATUS_STOP) && (action != PW_STATUS_START)) return -1; time_info = localtime(&rl.ut_time); /* Use start session time */ debug("acct: %s user='%s', port=%d, time=%d, input=%d, output=%d\n", (action==PW_STATUS_START)?"start":"stop", rl.login, rl.ent.port, rl.length, rl.inb, rl.outb); /* Prepare the DB filename... */ snprintf(dbfile_name,sizeof(dbfile_name),"%s/%d",radacct_dir,1900+time_info->tm_year); mkdir(dbfile_name,0755); snprintf(dbfile_name,sizeof(dbfile_name), "%s/%d/%s", radacct_dir,1900+time_info->tm_year,RADIUS_USER_STATS); dbf = gdbm_open(dbfile_name,0,GDBM_WRCREAT|GDBM_SYNC,0600,NULL ); if (dbf == NULL) { log_err("Could not open database %s for updating user stats", dbfile_name); return -1; } /* Build the key */ key.dptr = rl.login; key.dsize = strlen(rl.login); /* Search for a previous entry */ content = gdbm_fetch(dbf, key); if (content.dptr != NULL) { /* found */ retval = update_db_record(action, &content, &rl, time_info->tm_mon,time_info->tm_mday-1 ); if (retval < 0) { gdbm_close(dbf); if (content.dptr != NULL) free(content.dptr); return retval; } flag = GDBM_REPLACE; } else { /* key not found, insert new */ retval = insert_db_record(action, &content, &rl, time_info->tm_mon,time_info->tm_mday-1 ); if (retval < 0) { gdbm_close(dbf); if (content.dptr != NULL) free(content.dptr); return retval; } flag = GDBM_INSERT; } retval = gdbm_store(dbf, key, content, flag); gdbm_close(dbf); if (content.dptr != NULL) free(content.dptr); if (retval != 0) { log_err("acct: could not store entry for '%s' (session %s)\n", rl.login, (action==PW_STATUS_START)?"start":"stop"); return -2; } if (action == PW_STATUS_STOP) retval = update_radlast(&rl); return retval;}/* * shadow_expire - checks if an account is expired according to * the shadow aging fields */#if defined(SHADOW_EXPIRATION) && defined(SHADOW)#ifndef DAY#define DAY (3600*24)#endifint shadow_expired(const char *user){ struct spwd *spw; int crt_day = time(NULL)/DAY; /* today date */ int expire; if ((user == NULL) || !strlen(user)) { /* invalid call to this function */ debug("shadow_expired: called with null argument\n"); /* but the account is not expired... */ return 0; } debug("shadow_expired: checking shadow expiration for user '%s'\n", user); setspent(); spw = getspnam(user); if (spw == NULL) { /* Oops, sorry, all missing accounts are not expired :-) */ endspent(); return 0; } if ((spw->sp_expire > 0) && (spw->sp_expire < crt_day)) { /* Expired */ endspent(); return -1; } if (spw->sp_lstchg == 0) { /* expired by root */ endspent(); return -1; } if ((spw->sp_max <= 0) || (spw->sp_max == 99999)) { /* password never expires */ endspent(); return 0; } if (spw->sp_lstchg + spw->sp_max + spw->sp_inact < crt_day) { /* password expired - password aged */ endspent(); return -1; } /* be nice and also report when password is due to expire */ expire = spw->sp_lstchg + spw->sp_max + spw->sp_inact - crt_day; if ((expire >= 0) && (expire <= spw->sp_warn)) { /* warn the looser */ endspent(); return expire; } endspent(); return 0;}#endif #if defined(PAM) && defined(HAVE_LIBPAM)/* local variables */static const char *PAM_username;static const char *PAM_password;/* * Function: PAM_conv * Purpose: Dialogue between RADIUS and PAM modules. */static int PAM_conv_acct(int num_msg, const struct pam_message **msg,struct pam_response **resp, void *appdata_ptr){ int count = 0, replies = 0; struct pam_response *reply = NULL; int size = sizeof(struct pam_response); #define GET_MEM \ if (reply) realloc(reply, size); \ else reply = malloc(size); \ if (!reply) return PAM_CONV_ERR; \ size += sizeof(struct pam_response);#define COPY_STRING(s) (s) ? strdup(s) : NULL for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: GET_MEM; reply[replies].resp_retcode = PAM_SUCCESS; reply[replies++].resp = COPY_STRING(PAM_username); /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: GET_MEM; reply[replies].resp_retcode = PAM_SUCCESS; reply[replies++].resp = COPY_STRING(PAM_password); /* PAM frees resp */ break; case PAM_TEXT_INFO: /* ignore it... */ break; case PAM_ERROR_MSG: default: /* Must be an error of some sort... */ free (reply); return PAM_CONV_ERR; } } if (reply) *resp = reply; return PAM_SUCCESS;}static struct pam_conv conv_acct = { (int (*)())PAM_conv_acct, NULL};/* * Function: unix_pam * Purpose: Check the users password against the standard UNIX * password table + PAM. */int unix_pam(const char *name, const char *passwd, const char *pamauth){ pam_handle_t *pamh=NULL; int retval; PAM_username = name; PAM_password = passwd; debug("unix_PAM: using pamauth string <%s> for pam.conf lookup\n", pamauth); retval = pam_start(pamauth, name, &conv_acct, &pamh); if (retval == PAM_SUCCESS) { debug("unix_PAM: function pam_start succeeded for <%s>\n", name); retval = pam_authenticate(pamh, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -