const char *pr_strtime2(time_t t, int use_gmtime) { static char buf[64]; static char *mons[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; struct tm *tr; memset(buf, '\0', sizeof(buf)); if (use_gmtime) { tr = pr_gmtime(NULL, &t); } else { tr = pr_localtime(NULL, &t); } if (tr != NULL) { snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %d", days[tr->tm_wday], mons[tr->tm_mon], tr->tm_mday, tr->tm_hour, tr->tm_min, tr->tm_sec, tr->tm_year + 1900); } else { buf[0] = '\0'; } buf[sizeof(buf)-1] = '\0'; return buf; }
END_TEST START_TEST (localtime_test) { struct tm *res; time_t now; mark_point(); res = pr_localtime(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); time(&now); mark_point(); res = pr_localtime(NULL, &now); fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); mark_point(); res = pr_localtime(p, &now); fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); }
static void log_write(int priority, int f, char *s, int discard) { unsigned int max_priority = 0, *ptr = NULL; char serverinfo[PR_TUNABLE_BUFFER_SIZE] = {'\0'}; memset(serverinfo, '\0', sizeof(serverinfo)); if (main_server && main_server->ServerFQDN) { pr_netaddr_t *remote_addr = pr_netaddr_get_sess_remote_addr(); const char *remote_name = pr_netaddr_get_sess_remote_name(); snprintf(serverinfo, sizeof(serverinfo)-1, "%s", main_server->ServerFQDN); serverinfo[sizeof(serverinfo)-1] = '\0'; if (remote_addr && remote_name) { size_t serverinfo_len; serverinfo_len = strlen(serverinfo); snprintf(serverinfo + serverinfo_len, sizeof(serverinfo) - serverinfo_len, " (%s[%s])", remote_name, pr_netaddr_get_ipstr(remote_addr)); serverinfo[sizeof(serverinfo)-1] = '\0'; } } if (!discard && (logstderr || !main_server)) { char buf[LOGBUFFER_SIZE] = {'\0'}; size_t buflen, len; struct timeval now; struct tm *tm = NULL; unsigned long millis; gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); if (tm == NULL) { return; } len = strftime(buf, sizeof(buf)-1, "%Y-%m-%d %H:%M:%S", tm); buflen = len; buf[sizeof(buf)-1] = '\0'; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis); buflen += len; buf[sizeof(buf)-1] = '\0'; if (*serverinfo) { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u] %s: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), serverinfo, s); } else { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u]: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), s); } buflen += len; buf[sizeof(buf)-1] = '\0'; pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, STDERR_FILENO, priority, buf, buflen); fprintf(stderr, "%s", buf); return; } if (syslog_discard) { /* Only return now if we don't have any log listeners. */ if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 && pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) { return; } } ptr = get_param_ptr(main_server->conf, "SyslogLevel", FALSE); if (ptr != NULL) { max_priority = *ptr; } else { /* Default SyslogLevel */ max_priority = default_level; } if (priority > max_priority) { /* Only return now if we don't have any log listeners. */ if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 && pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) { return; } } if (systemlog_fd != -1) { char buf[LOGBUFFER_SIZE] = {'\0'}; size_t buflen, len; struct timeval now; struct tm *tm; unsigned long millis; gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); if (tm == NULL) { return; } len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); buflen = len; buf[sizeof(buf) - 1] = '\0'; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis); buflen += len; buf[sizeof(buf) - 1] = '\0'; if (*serverinfo) { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u] %s: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), serverinfo, s); } else { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u]: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), s); } buflen += len; buf[sizeof(buf)-1] = '\0'; pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, systemlog_fd, priority, buf, buflen); /* Now we need to enforce the discard, syslog_discard and SyslogLevel * filtering. */ if (discard) { return; } if (syslog_discard) { return; } if (priority > max_priority) { return; } while (write(systemlog_fd, buf, buflen) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } return; } return; } pr_log_event_generate(PR_LOG_TYPE_SYSLOG, syslog_sockfd, priority, s, strlen(s)); if (set_facility != -1) f = set_facility; if (!syslog_open) { syslog_sockfd = pr_openlog("proftpd", LOG_NDELAY|LOG_PID, f); if (syslog_sockfd < 0) { (void) pr_trace_msg(trace_channel, 1, "error opening syslog fd: %s", strerror(errno)); return; } syslog_open = TRUE; } else if (f != facility) { /* If this message is to be sent to a different log facility than a * default one (or the facility configured via SyslogFacility), then * OR in the facility with the priority value, as per the syslog(3) * docs. */ priority |= f; } if (*serverinfo) { pr_syslog(syslog_sockfd, priority, "%s - %s\n", serverinfo, s); } else { pr_syslog(syslog_sockfd, priority, "%s\n", s); } }
int pr_log_vwritefile(int logfd, const char *ident, const char *fmt, va_list msg) { char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'}; struct timeval now; struct tm *tm = NULL; size_t buflen, len; unsigned long millis; if (logfd < 0) { errno = EINVAL; return -1; } gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); if (tm == NULL) { return -1; } /* Prepend the timestamp */ len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); buflen = len; buf[sizeof(buf)-1] = '\0'; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis); buflen += len; /* Prepend a small header */ len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s[%u]: ", ident, (unsigned int) (session.pid ? session.pid : getpid())); buflen += len; buf[sizeof(buf)-1] = '\0'; /* Affix the message */ len = vsnprintf(buf + buflen, sizeof(buf) - buflen - 1, fmt, msg); buflen += len; buf[sizeof(buf)-1] = '\0'; if (buflen < (sizeof(buf) - 1)) { buf[buflen++] = '\n'; } else { buf[sizeof(buf)-2] = '\n'; buflen++; } pr_log_event_generate(PR_LOG_TYPE_UNSPEC, logfd, -1, buf, buflen); while (write(logfd, buf, buflen) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } return -1; } return 0; }
static int trace_write(const char *channel, int level, const char *msg, int discard) { char buf[PR_TUNABLE_BUFFER_SIZE]; size_t buflen, len; struct tm *tm; int use_conn_ips = FALSE; if (trace_logfd < 0) return 0; memset(buf, '\0', sizeof(buf)); if (!(trace_opts & PR_TRACE_OPT_USE_TIMESTAMP_MILLIS)) { time_t now; now = time(NULL); tm = pr_localtime(NULL, &now); len = strftime(buf, sizeof(buf)-1, "%Y-%m-%d %H:%M:%S", tm); buflen = len; } else { struct timeval now; unsigned long millis; gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); len = strftime(buf, sizeof(buf)-1, "%Y-%m-%d %H:%M:%S", tm); buflen = len; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - buflen, ",%03lu", millis); buflen += len; } if ((trace_opts & PR_TRACE_OPT_LOG_CONN_IPS) && session.c != NULL) { /* We can only support the "+ConnIPs" TraceOption if there actually * is a client connected in this process. We might be the daemon * process, in which there is no client. */ use_conn_ips = TRUE; } if (use_conn_ips == FALSE) { len = snprintf(buf + buflen, sizeof(buf) - buflen, " [%u] <%s:%d>: %s", (unsigned int) (session.pid ? session.pid : getpid()), channel, level, msg); buflen += len; } else { const char *client_ip, *server_ip; int server_port; client_ip = pr_netaddr_get_ipstr(session.c->remote_addr); server_ip = pr_netaddr_get_ipstr(session.c->local_addr); server_port = pr_netaddr_get_port(session.c->local_addr); len = snprintf(buf + buflen, sizeof(buf) - buflen, " [%u] (client %s, server %s:%d) <%s:%d>: %s", (unsigned int) (session.pid ? session.pid : getpid()), client_ip != NULL ? client_ip : "none", server_ip != NULL ? server_ip : "none", server_port, channel, level, msg); buflen += len; } buf[sizeof(buf)-1] = '\0'; if (buflen < (sizeof(buf) - 1)) { buf[buflen] = '\n'; buflen++; } else { buf[sizeof(buf)-2] = '\n'; } pr_log_event_generate(PR_LOG_TYPE_TRACELOG, trace_logfd, level, buf, buflen); if (discard) { /* This log message would not have been written to disk, so just discard * it. The discard value is TRUE when there's a log listener for * TraceLog logging events, and the Trace log level configuration would * otherwise have filtered out this log message. */ return 0; } return write(trace_logfd, buf, buflen); }
const char *sftp_display_fh_get_msg(pool *p, pr_fh_t *fh) { struct stat st; char buf[PR_TUNABLE_BUFFER_SIZE], *msg = ""; int len, res; unsigned int *current_clients = NULL; unsigned int *max_clients = NULL; off_t fs_size = 0; void *v; const char *serverfqdn = main_server->ServerFQDN; char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'}, mg_max[12] = "unlimited"; char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'}, mg_cur_class[12] = {'\0'}; const char *mg_time; char *rfc1413_ident = NULL, *user = NULL; /* Stat the opened file to determine the optimal buffer size for IO. */ memset(&st, 0, sizeof(st)); if (pr_fsio_fstat(fh, &st) == 0) { fh->fh_iosz = st.st_blksize; } res = pr_fs_fgetsize(fh->fh_fd, &fs_size); if (res < 0 && errno != ENOSYS) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error getting filesystem size for '%s': %s", fh->fh_path, strerror(errno)); fs_size = 0; } snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size); format_size_str(mg_size_units, sizeof(mg_size_units), fs_size); mg_time = pr_strtime(time(NULL)); max_clients = get_param_ptr(main_server->conf, "MaxClients", FALSE); v = pr_table_get(session.notes, "client-count", NULL); if (v) { current_clients = v; } snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1); if (session.conn_class != NULL && session.conn_class->cls_name) { unsigned int *class_clients = NULL; config_rec *maxc = NULL; unsigned int maxclients = 0; v = pr_table_get(session.notes, "class-client-count", NULL); if (v) { class_clients = v; } snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", class_clients ? *class_clients : 0); /* For the %z variable, first we scan through the MaxClientsPerClass, * and use the first applicable one. If none are found, look for * any MaxClients set. */ maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass", FALSE); while (maxc) { pr_signals_handle(); if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) { maxc = find_config_next(maxc, maxc->next, CONF_PARAM, "MaxClientsPerClass", FALSE); continue; } maxclients = *((unsigned int *) maxc->argv[1]); break; } if (maxclients == 0) { maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE); if (maxc) maxclients = *((unsigned int *) maxc->argv[0]); } snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients); } else { snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", max_clients ? *max_clients : 0); snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0); } snprintf(mg_max, sizeof(mg_max), "%u", max_clients ? *max_clients : 0); user = pr_table_get(session.notes, "mod_auth.orig-user", NULL); if (user == NULL) user = ""; rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL); if (rfc1413_ident == NULL) { rfc1413_ident = "UNKNOWN"; } memset(buf, '\0', sizeof(buf)); while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) { char *tmp; pr_signals_handle(); buf[sizeof(buf)-1] = '\0'; len = strlen(buf); while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) { pr_signals_handle(); buf[len-1] = '\0'; len--; } /* Check for any Variable-type strings. */ tmp = strstr(buf, "%{"); while (tmp) { char *key, *tmp2; const char *val; pr_signals_handle(); tmp2 = strchr(tmp, '}'); if (tmp2 == NULL) { /* No closing '}' found in this string, so no need to look for any * aother '%{' opening sequence. Just move on. */ tmp = NULL; break; } key = pstrndup(p, tmp, tmp2 - tmp + 1); /* There are a couple of special-case keys to watch for: * * env:$var * time:$fmt * * The Var API does not easily support returning values for keys * where part of the value depends on part of the key. That's why * these keys are handled here, instead of in pr_var_get(). */ if (strncmp(key, "%{time:", 7) == 0) { char time_str[128], *fmt; time_t now; struct tm *time_info; fmt = pstrndup(p, key + 7, strlen(key) - 8); now = time(NULL); time_info = pr_localtime(NULL, &now); memset(time_str, 0, sizeof(time_str)); strftime(time_str, sizeof(time_str), fmt, time_info); val = pstrdup(p, time_str); } else if (strncmp(key, "%{env:", 6) == 0) { char *env_var; env_var = pstrndup(p, key + 6, strlen(key) - 7); val = pr_env_get(p, env_var); if (val == NULL) { pr_trace_msg("var", 4, "no value set for environment variable '%s', using \"(none)\"", env_var); val = "(none)"; } } else { val = pr_var_get(key); if (val == NULL) { pr_trace_msg("var", 4, "no value set for name '%s', using \"(none)\"", key); val = "(none)"; } } outs = sreplace(p, buf, key, val, NULL); sstrncpy(buf, outs, sizeof(buf)); tmp = strstr(outs, "%{"); } outs = sreplace(p, buf, "%C", (session.cwd[0] ? session.cwd : "(none)"), "%E", main_server->ServerAdmin, "%F", mg_size, "%f", mg_size_units, "%i", "0", "%K", "0", "%k", "0B", "%L", serverfqdn, "%M", mg_max, "%N", mg_cur, "%o", "0", "%R", (session.c && session.c->remote_name ? session.c->remote_name : "(unknown)"), "%T", mg_time, "%t", "0", "%U", user, "%u", rfc1413_ident, "%V", main_server->ServerName, "%x", session.conn_class ? session.conn_class->cls_name : "(unknown)", "%y", mg_cur_class, "%z", mg_class_limit, NULL); /* Always make sure that the lines we send are CRLF-terminated. */ msg = pstrcat(p, msg, outs, "\r\n", NULL); /* Clear the buffer for the next read. */ memset(buf, '\0', sizeof(buf)); } return msg; }
/* Checks for the existence of PR_SHUTMSG_PATH. deny and disc are * filled with the times to deny new connections and disconnect * existing ones. */ int check_shutmsg(const char *path, time_t *shut, time_t *deny, time_t *disc, char *msg, size_t msg_size) { FILE *fp; char *deny_str, *disc_str, *cp, buf[PR_TUNABLE_BUFFER_SIZE+1] = {'\0'}; char hr[3] = {'\0'}, mn[3] = {'\0'}; time_t now, shuttime = (time_t) 0; struct tm *tm; if (path == NULL) { errno = EINVAL; return -1; } fp = fopen(path, "r"); if (fp != NULL) { struct stat st; if (fstat(fileno(fp), &st) == 0) { if (S_ISDIR(st.st_mode)) { fclose(fp); errno = EISDIR; return -1; } } cp = fgets(buf, sizeof(buf), fp); if (cp != NULL) { buf[sizeof(buf)-1] = '\0'; CHOP(cp); /* We use this to fill in dst, timezone, etc */ time(&now); tm = pr_localtime(NULL, &now); if (tm == NULL) { fclose(fp); return 0; } tm->tm_year = atoi(safe_token(&cp)) - 1900; tm->tm_mon = atoi(safe_token(&cp)) - 1; tm->tm_mday = atoi(safe_token(&cp)); tm->tm_hour = atoi(safe_token(&cp)); tm->tm_min = atoi(safe_token(&cp)); tm->tm_sec = atoi(safe_token(&cp)); deny_str = safe_token(&cp); disc_str = safe_token(&cp); shuttime = mktime(tm); if (shuttime == (time_t) -1) { fclose(fp); return 0; } if (deny != NULL) { if (strlen(deny_str) == 4) { sstrncpy(hr, deny_str, sizeof(hr)); hr[2] = '\0'; deny_str += 2; sstrncpy(mn, deny_str, sizeof(mn)); mn[2] = '\0'; *deny = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60)); } else { *deny = shuttime; } } if (disc != NULL) { if (strlen(disc_str) == 4) { sstrncpy(hr, disc_str, sizeof(hr)); hr[2] = '\0'; disc_str += 2; sstrncpy(mn, disc_str, sizeof(mn)); mn[2] = '\0'; *disc = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60)); } else { *disc = shuttime; } } if (fgets(buf, sizeof(buf), fp) && msg) { buf[sizeof(buf)-1] = '\0'; CHOP(buf); sstrncpy(msg, buf, msg_size-1); } } fclose(fp); if (shut != NULL) { *shut = shuttime; } return 1; } return -1; }