/* * The Date header must indicate a time within 3600 seconds of the receipt of a * message. RFC 4474 [6] Step 4 */ static int check_date(struct sip_msg* msg, char* srt1, char* str2) { time_t tnow, tmsg; int ires; ires=datehdr_proc(NULL, NULL, msg); if (ires) return -1; #ifdef HAVE_TIMEGM tmsg=timegm(&get_date(msg)->date); #else tmsg=_timegm(&get_date(msg)->date); #endif if (tmsg < 0) { LOG(L_ERR, "AUTH_IDENTITY:check_date: timegm error\n"); return -2; } if ((tnow=time(0)) < 0) { LOG(L_ERR, "AUTH_IDENTITY:check_date: time error %s\n", strerror(errno)); return -3; } if (tnow > tmsg + glb_iauthval) { LOG(L_INFO, "AUTH_IDENTITY VERIFIER: Outdated date header value (%ld sec)\n", tnow - tmsg + glb_iauthval); return -4; } else LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Date header value OK\n"); return 1; }
/* Convert time_t value in UTC to to value relative to local time zone */ time_t utc2local(time_t in) { struct tm* tt; tt = localtime(&in); #ifdef HAVE_TIMEGM return timegm(tt); #else return _timegm(tt); #endif }
static inline int ldap_gentime2db_datetime(time_t* dst, str* src) { struct tm time; if (src->len < 12) return -1; /* It is necessary to zero tm structure first */ memset(&time, '\0', sizeof(struct tm)); /* YYYYMMDDHHMMSS[.sss][ 'Z' | ( {'+'|'-'} ZZZZ) ] */ strptime(src->s, "%Y%m%d%H%M%S", &time); /* Note: frac of seconds are lost in time_t representation */ if (src->s[src->len-1] == 'Z' || src->s[src->len-5] == '-' || src->s[src->len-5] == '+') { /* GMT or specified TZ, no daylight saving time */ #ifdef HAVE_TIMEGM *dst = timegm(&time); #else *dst = _timegm(&time); #endif /* HAVE_TIMEGM */ if (src->s[src->len-1] != 'Z') { /* timezone is specified */ memset(&time, '\0', sizeof(struct tm)); strptime(src->s + src->len - 4, "%H%M", &time); switch (src->s[src->len-5]) { case '-': *dst -= time.tm_hour*3600+time.tm_min*60; break; case '+': *dst += time.tm_hour*3600+time.tm_min*60; break; default: ; } } } else { /* it's local time */ /* Daylight saving information got lost in the database * so let timegm to guess it. This eliminates the bug when * contacts reloaded from the database have different time * of expiration by one hour when daylight saving is used */ time.tm_isdst = -1; *dst = timelocal(&time); } return 0; }
static void test_schedule_get(void) { crono_schedule cs; struct tm tm; init_schedule(&cs); cs.f[crono_SECOND].pos = 0; cs.f[crono_MINUTE].pos = 59; cs.f[crono_HOUR].pos = 13; cs.f[crono_DAY].pos = 13; cs.f[crono_MONTH].pos = 11; cs.f[crono_YEAR].pos = 2013; crono_schedule_get(&cs, &tm); time_t tt = _timegm(&tm); if (!is(tt, 1384351140, "time set")) diag("wanted 1384351140, got %ld", (long) tt); }
/** * Builds UPDATE statement where cmd->valss specify column name-value pairs * and cmd->match specify WHERE clause. * @param sql_cmd SQL statement as a result of this function * @param cmd input for statement creation */ static int build_update_cmd(str* sql_cmd, db_cmd_t* cmd) { struct string_buffer sql_buf = {.s = NULL, .len = 0, .size = 0, .increment = 128}; db_fld_t* fld; int i; int rv = 0; str tmpstr; rv = sb_add(&sql_buf, &strings[STR_UPDATE]); /* "UPDATE " */ rv |= sb_add(&sql_buf, &cmd->table); /* table name */ rv |= sb_add(&sql_buf, &strings[STR_SET]); /* " SET " */ /* column name-value pairs */ for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) { rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name)); rv |= sb_add(&sql_buf, set_str(&tmpstr, " = ")); rv |= sb_add(&sql_buf, &strings[STR_ESC]); if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ", ")); } if (rv) { goto err; } if (!DB_FLD_EMPTY(cmd->match)) { rv |= sb_add(&sql_buf, &strings[STR_WHERE]); for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) { rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name)); switch(fld[i].op) { case DB_EQ: rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]); break; case DB_NE: rv |= sb_add(&sql_buf, &strings[STR_OP_NE]); break; case DB_LT: rv |= sb_add(&sql_buf, &strings[STR_OP_LT]); break; case DB_GT: rv |= sb_add(&sql_buf, &strings[STR_OP_GT]); break; case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break; case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break; } rv |= sb_add(&sql_buf, &strings[STR_ESC]); if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]); } } rv |= sb_add(&sql_buf, set_str(&tmpstr, "\0")); if (rv) { goto err; } sql_cmd->s = sql_buf.s; sql_cmd->len = sql_buf.len; return 0; err: if (sql_buf.s) pkg_free(sql_buf.s); return -1; } static inline void update_field(MYSQL_BIND *param, db_fld_t* fld) { struct my_fld* fp; /* field payload */ struct tm* t; fp = DB_GET_PAYLOAD(fld); #ifndef MYSQL_FAKE_NULL fp->is_null = fld->flags & DB_NULL; if (fp->is_null) return; #else if (fld->flags & DB_NULL) { switch(fld->type) { case DB_STR: case DB_CSTR: param->buffer = FAKE_NULL_STR.s; fp->length = FAKE_NULL_STR.len; break; case DB_INT: *(int*)param->buffer = FAKE_NULL_INT; break; case DB_BLOB: case DB_DATETIME: case DB_NONE: case DB_FLOAT: case DB_DOUBLE: case DB_BITMAP: /* we don't have fake null value for these types */ fp->is_null = DB_NULL; break; } return; } #endif switch(fld->type) { case DB_STR: param->buffer = fld->v.lstr.s; fp->length = fld->v.lstr.len; break; case DB_BLOB: param->buffer = fld->v.blob.s; fp->length = fld->v.blob.len; break; case DB_CSTR: param->buffer = (char*)fld->v.cstr; fp->length = strlen(fld->v.cstr); break; case DB_DATETIME: t = gmtime(&fld->v.time); fp->time.second = t->tm_sec; fp->time.minute = t->tm_min; fp->time.hour = t->tm_hour; fp->time.day = t->tm_mday; fp->time.month = t->tm_mon + 1; fp->time.year = t->tm_year + 1900; break; case DB_NONE: case DB_INT: case DB_FLOAT: case DB_DOUBLE: case DB_BITMAP: /* No need to do anything for these types */ break; } } /** * Update values of MySQL bound parameters with values from * the DB API. * @param cmd Command structure which contains pointers to MYSQL_STMT and parameters values * @see bind_mysql_params */ static inline void set_mysql_params(db_cmd_t* cmd) { struct my_cmd* mcmd; int i; mcmd = DB_GET_PAYLOAD(cmd); /* FIXME: We are updating internals of the prepared statement here, * this is probably not nice but I could not find another way of * updating the pointer to the buffer without the need to run * mysql_stmt_bind_param again (which would be innefficient) */ for(i = 0; i < cmd->vals_count; i++) { update_field(mcmd->st->params + i, cmd->vals + i); } for(i = 0; i < cmd->match_count; i++) { update_field(mcmd->st->params + cmd->vals_count + i, cmd->match + i); } } static inline int update_result(db_fld_t* result, MYSQL_STMT* st) { int i; struct my_fld* rp; /* Payload of the current field in result */ struct tm t; /* Iterate through all the fields returned by MySQL and convert * them to DB API representation if necessary */ for(i = 0; i < st->field_count; i++) { rp = DB_GET_PAYLOAD(result + i); if (rp->is_null) { result[i].flags |= DB_NULL; continue; } else { result[i].flags &= ~DB_NULL; } switch(result[i].type) { case DB_STR: result[i].v.lstr.len = rp->length; #ifdef MYSQL_FAKE_NULL if (STR_EQ(FAKE_NULL_STR,result[i].v.lstr)) { result[i].flags |= DB_NULL; } #endif break; case DB_BLOB: result[i].v.blob.len = rp->length; break; case DB_CSTR: if (rp->length < STR_BUF_SIZE) { result[i].v.cstr[rp->length] = '\0'; } else { /* Truncated field but rp->length contains full size, * zero terminated the last byte in the buffer */ result[i].v.cstr[STR_BUF_SIZE - 1] = '\0'; } #ifdef MYSQL_FAKE_NULL if (strcmp(FAKE_NULL_STR.s,result[i].v.cstr)==0) { result[i].flags |= DB_NULL; } #endif break; case DB_DATETIME: memset(&t, '\0', sizeof(struct tm)); t.tm_sec = rp->time.second; t.tm_min = rp->time.minute; t.tm_hour = rp->time.hour; t.tm_mday = rp->time.day; t.tm_mon = rp->time.month - 1; t.tm_year = rp->time.year - 1900; /* Daylight saving information got lost in the database * so let timegm to guess it. This eliminates the bug when * contacts reloaded from the database have different time * of expiration by one hour when daylight saving is used */ t.tm_isdst = -1; #ifdef HAVE_TIMEGM result[i].v.time = timegm(&t); #else result[i].v.time = _timegm(&t); #endif /* HAVE_TIMEGM */ break; case DB_INT: #ifdef MYSQL_FAKE_NULL if (FAKE_NULL_INT==result[i].v.int4) { result[i].flags |= DB_NULL; } break; #endif case DB_NONE: case DB_FLOAT: case DB_DOUBLE: case DB_BITMAP: /* No need to do anything for these types */ break; } } return 0; }
/* Checks the Date header of the message. RFC4474 [5] Step 3 */ static int date_proc(struct sip_msg* msg, char* srt1, char* str2) { str sdate; int iRes; time_t tmsg, tnow; if (glb_authservice_disabled) { LOG(L_WARN, "AUTH_IDENTITY:date_proc: Authentication Service is disabled\n"); return -1; } getstr_dynstr(&glb_sdate).len=0; /* we'd like to get the DATE header of the massage */ iRes=datehdr_proc(&sdate, NULL, msg); switch (iRes) { case AUTH_ERROR: return -1; case AUTH_NOTFOUND: if (append_date(&getstr_dynstr(&glb_sdate), glb_sdate.size, &tmsg, msg)) return -2; break; /* Message has Date header so we check that */ case AUTH_OK: #ifdef HAVE_TIMEGM tmsg=timegm(&get_date(msg)->date); #else tmsg=_timegm(&get_date(msg)->date); #endif if (tmsg < 0) { LOG(L_ERR, "AUTH_IDENTITY:date_proc: timegm error\n"); return -3; } if ((tnow=time(NULL))<0) { LOG(L_ERR, "AUTH_IDENTITY:date_proc: time error\n"); return -4; } /* * If the value of this field contains a time different by more than * ten minutes from the current time noted by the authentication * service then it should reject the message. */ if (tmsg + glb_imsgtime < tnow || tnow + glb_imsgtime < tmsg) { LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: Date header overdue\n"); return -6; } break; default: /* unknown result */ return -7; } /* * The authentication service MUST verify that the Date header * falls within the validity period of its certificate * RFC 4474 [6] Step 3 */ if (glb_imycertnotafter < tmsg) { LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: My certificate has been expired\n"); return -8; } return 1; }