mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
e4f5bfb34b
This API is unusual in that if used to remove a non-list head it nulls out the next and prev pointers. This is what you want for debugging (don't want an entry removed from the list to be still virtually linked into it) but means there is no consistent idiom for use as the next and prev pointers get trashed on removal from the list, meaning you must save them yourself. You can use it one way when deleting everything via the head pointer, as this preserves the next pointer, but you *must* use it another way when not deleting everything via the head pointer. Fix all known uses of this (the main one is in conn_free_internal() and would not free all the private data entries for vfs modules. The other changes in web/statuspage.c and winbindd_util.c are not strictly neccessary, as the head pointer is being used, but I've done them for consistency. Long term we must revisit this as this API is too hard to use correctly. Jeremy.
455 lines
12 KiB
C
455 lines
12 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
web status page
|
|
Copyright (C) Andrew Tridgell 1997-1998
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "web/swat_proto.h"
|
|
|
|
#define _(x) lang_msg_rotate(talloc_tos(),x)
|
|
|
|
#define PIDMAP struct PidMap
|
|
|
|
/* how long to wait for start/stops to take effect */
|
|
#define SLEEP_TIME 3
|
|
|
|
PIDMAP {
|
|
PIDMAP *next, *prev;
|
|
struct server_id pid;
|
|
char *machine;
|
|
};
|
|
|
|
static PIDMAP *pidmap;
|
|
static int PID_or_Machine; /* 0 = show PID, else show Machine name */
|
|
|
|
static struct server_id smbd_pid;
|
|
|
|
/* from 2nd call on, remove old list */
|
|
static void initPid2Machine (void)
|
|
{
|
|
/* show machine name rather PID on table "Open Files"? */
|
|
if (PID_or_Machine) {
|
|
PIDMAP *p, *next;
|
|
|
|
for (p = pidmap; p != NULL; p = next) {
|
|
next = p->next;
|
|
DLIST_REMOVE(pidmap, p);
|
|
SAFE_FREE(p->machine);
|
|
SAFE_FREE(p);
|
|
}
|
|
|
|
pidmap = NULL;
|
|
}
|
|
}
|
|
|
|
/* add new PID <-> Machine name mapping */
|
|
static void addPid2Machine (struct server_id pid, const char *machine)
|
|
{
|
|
/* show machine name rather PID on table "Open Files"? */
|
|
if (PID_or_Machine) {
|
|
PIDMAP *newmap;
|
|
|
|
if ((newmap = SMB_MALLOC_P(PIDMAP)) == NULL) {
|
|
/* XXX need error message for this?
|
|
if malloc fails, PID is always shown */
|
|
return;
|
|
}
|
|
|
|
newmap->pid = pid;
|
|
newmap->machine = SMB_STRDUP(machine);
|
|
|
|
DLIST_ADD(pidmap, newmap);
|
|
}
|
|
}
|
|
|
|
/* lookup PID <-> Machine name mapping */
|
|
static char *mapPid2Machine (struct server_id pid)
|
|
{
|
|
static char pidbuf [64];
|
|
PIDMAP *map;
|
|
|
|
/* show machine name rather PID on table "Open Files"? */
|
|
if (PID_or_Machine) {
|
|
for (map = pidmap; map != NULL; map = map->next) {
|
|
if (procid_equal(&pid, &map->pid)) {
|
|
if (map->machine == NULL) /* no machine name */
|
|
break; /* show PID */
|
|
|
|
return map->machine;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* PID not in list or machine name NULL? return pid as string */
|
|
snprintf (pidbuf, sizeof (pidbuf) - 1, "%s",
|
|
procid_str_static(&pid));
|
|
return pidbuf;
|
|
}
|
|
|
|
static const char *tstring(TALLOC_CTX *ctx, time_t t)
|
|
{
|
|
char *buf;
|
|
buf = talloc_strdup(ctx, time_to_asc(t));
|
|
if (!buf) {
|
|
return "";
|
|
}
|
|
buf = talloc_all_string_sub(ctx,
|
|
buf,
|
|
" ",
|
|
" ");
|
|
if (!buf) {
|
|
return "";
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static void print_share_mode(const struct share_mode_entry *e,
|
|
const char *sharepath,
|
|
const char *fname,
|
|
void *dummy)
|
|
{
|
|
char *utf8_fname;
|
|
int deny_mode;
|
|
size_t converted_size;
|
|
|
|
if (!is_valid_share_mode_entry(e)) {
|
|
return;
|
|
}
|
|
|
|
deny_mode = map_share_mode_to_deny_mode(e->share_access,
|
|
e->private_options);
|
|
|
|
printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid)));
|
|
printf("<td>%u</td>",(unsigned int)e->uid);
|
|
printf("<td>");
|
|
switch ((deny_mode>>4)&0xF) {
|
|
case DENY_NONE: printf("DENY_NONE"); break;
|
|
case DENY_ALL: printf("DENY_ALL "); break;
|
|
case DENY_DOS: printf("DENY_DOS "); break;
|
|
case DENY_FCB: printf("DENY_FCB "); break;
|
|
case DENY_READ: printf("DENY_READ "); break;
|
|
case DENY_WRITE:printf("DENY_WRITE "); break;
|
|
}
|
|
printf("</td>");
|
|
|
|
printf("<td>");
|
|
if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) {
|
|
printf("%s", _("RDWR "));
|
|
} else if (e->access_mask & FILE_WRITE_DATA) {
|
|
printf("%s", _("WRONLY "));
|
|
} else {
|
|
printf("%s", _("RDONLY "));
|
|
}
|
|
printf("</td>");
|
|
|
|
printf("<td>");
|
|
if((e->op_type &
|
|
(EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
|
|
(EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
|
|
printf("EXCLUSIVE+BATCH ");
|
|
else if (e->op_type & EXCLUSIVE_OPLOCK)
|
|
printf("EXCLUSIVE ");
|
|
else if (e->op_type & BATCH_OPLOCK)
|
|
printf("BATCH ");
|
|
else if (e->op_type & LEVEL_II_OPLOCK)
|
|
printf("LEVEL_II ");
|
|
else
|
|
printf("NONE ");
|
|
printf("</td>");
|
|
|
|
push_utf8_allocate(&utf8_fname, fname, &converted_size);
|
|
printf("<td>%s</td><td>%s</td></tr>\n",
|
|
utf8_fname,tstring(talloc_tos(),e->time.tv_sec));
|
|
SAFE_FREE(utf8_fname);
|
|
}
|
|
|
|
|
|
/* kill off any connections chosen by the user */
|
|
static int traverse_fn1(struct db_record *rec,
|
|
const struct connections_key *key,
|
|
const struct connections_data *crec,
|
|
void *private_data)
|
|
{
|
|
if (crec->cnum == -1 && process_exists(crec->pid)) {
|
|
char buf[30];
|
|
slprintf(buf,sizeof(buf)-1,"kill_%s", procid_str_static(&crec->pid));
|
|
if (cgi_variable(buf)) {
|
|
kill_pid(crec->pid);
|
|
sleep(SLEEP_TIME);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* traversal fn for showing machine connections */
|
|
static int traverse_fn2(struct db_record *rec,
|
|
const struct connections_key *key,
|
|
const struct connections_data *crec,
|
|
void *private_data)
|
|
{
|
|
if (crec->cnum == -1 || !process_exists(crec->pid) ||
|
|
procid_equal(&crec->pid, &smbd_pid))
|
|
return 0;
|
|
|
|
addPid2Machine (crec->pid, crec->machine);
|
|
|
|
printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>\n",
|
|
procid_str_static(&crec->pid),
|
|
crec->machine, crec->addr,
|
|
tstring(talloc_tos(),crec->start));
|
|
if (geteuid() == 0) {
|
|
printf("<td><input type=submit value=\"X\" name=\"kill_%s\"></td>\n",
|
|
procid_str_static(&crec->pid));
|
|
}
|
|
printf("</tr>\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* traversal fn for showing share connections */
|
|
static int traverse_fn3(struct db_record *rec,
|
|
const struct connections_key *key,
|
|
const struct connections_data *crec,
|
|
void *private_data)
|
|
{
|
|
if (crec->cnum == -1 || !process_exists(crec->pid))
|
|
return 0;
|
|
|
|
printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
|
|
crec->servicename, uidtoname(crec->uid),
|
|
gidtoname(crec->gid),procid_str_static(&crec->pid),
|
|
crec->machine,
|
|
tstring(talloc_tos(),crec->start));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* show the current server status */
|
|
void status_page(void)
|
|
{
|
|
const char *v;
|
|
int autorefresh=0;
|
|
int refresh_interval=30;
|
|
int nr_running=0;
|
|
bool waitup = False;
|
|
TALLOC_CTX *ctx = talloc_stackframe();
|
|
|
|
smbd_pid = pid_to_procid(pidfile_pid("smbd"));
|
|
|
|
if (cgi_variable("smbd_restart") || cgi_variable("all_restart")) {
|
|
stop_smbd();
|
|
start_smbd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("smbd_start") || cgi_variable("all_start")) {
|
|
start_smbd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("smbd_stop") || cgi_variable("all_stop")) {
|
|
stop_smbd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("nmbd_restart") || cgi_variable("all_restart")) {
|
|
stop_nmbd();
|
|
start_nmbd();
|
|
waitup=True;
|
|
}
|
|
if (cgi_variable("nmbd_start") || cgi_variable("all_start")) {
|
|
start_nmbd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("nmbd_stop")|| cgi_variable("all_stop")) {
|
|
stop_nmbd();
|
|
waitup=True;
|
|
}
|
|
|
|
#ifdef WITH_WINBIND
|
|
if (cgi_variable("winbindd_restart") || cgi_variable("all_restart")) {
|
|
stop_winbindd();
|
|
start_winbindd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("winbindd_start") || cgi_variable("all_start")) {
|
|
start_winbindd();
|
|
waitup=True;
|
|
}
|
|
|
|
if (cgi_variable("winbindd_stop") || cgi_variable("all_stop")) {
|
|
stop_winbindd();
|
|
waitup=True;
|
|
}
|
|
#endif
|
|
/* wait for daemons to start/stop */
|
|
if (waitup)
|
|
sleep(SLEEP_TIME);
|
|
|
|
if (cgi_variable("autorefresh")) {
|
|
autorefresh = 1;
|
|
} else if (cgi_variable("norefresh")) {
|
|
autorefresh = 0;
|
|
} else if (cgi_variable("refresh")) {
|
|
autorefresh = 1;
|
|
}
|
|
|
|
if ((v=cgi_variable("refresh_interval"))) {
|
|
refresh_interval = atoi(v);
|
|
}
|
|
|
|
if (cgi_variable("show_client_in_col_1")) {
|
|
PID_or_Machine = 1;
|
|
}
|
|
|
|
if (cgi_variable("show_pid_in_col_1")) {
|
|
PID_or_Machine = 0;
|
|
}
|
|
|
|
connections_forall(traverse_fn1, NULL);
|
|
|
|
initPid2Machine ();
|
|
|
|
printf("<H2>%s</H2>\n", _("Server Status"));
|
|
|
|
printf("<FORM method=post>\n");
|
|
|
|
if (!autorefresh) {
|
|
printf("<input type=submit value=\"%s\" name=\"autorefresh\">\n", _("Auto Refresh"));
|
|
printf("<br>%s", _("Refresh Interval: "));
|
|
printf("<input type=text size=2 name=\"refresh_interval\" value=\"%d\">\n",
|
|
refresh_interval);
|
|
} else {
|
|
printf("<input type=submit value=\"%s\" name=\"norefresh\">\n", _("Stop Refreshing"));
|
|
printf("<br>%s%d\n", _("Refresh Interval: "), refresh_interval);
|
|
printf("<input type=hidden name=\"refresh\" value=\"1\">\n");
|
|
}
|
|
|
|
printf("<p>\n");
|
|
|
|
printf("<table>\n");
|
|
|
|
printf("<tr><td>%s</td><td>%s</td></tr>", _("version:"), SAMBA_VERSION_STRING);
|
|
|
|
fflush(stdout);
|
|
printf("<tr><td>%s</td><td>%s</td>\n", _("smbd:"), smbd_running()?_("running"):_("not running"));
|
|
if (geteuid() == 0) {
|
|
if (smbd_running()) {
|
|
nr_running++;
|
|
printf("<td><input type=submit name=\"smbd_stop\" value=\"%s\"></td>\n", _("Stop smbd"));
|
|
} else {
|
|
printf("<td><input type=submit name=\"smbd_start\" value=\"%s\"></td>\n", _("Start smbd"));
|
|
}
|
|
printf("<td><input type=submit name=\"smbd_restart\" value=\"%s\"></td>\n", _("Restart smbd"));
|
|
}
|
|
printf("</tr>\n");
|
|
|
|
fflush(stdout);
|
|
printf("<tr><td>%s</td><td>%s</td>\n", _("nmbd:"), nmbd_running()?_("running"):_("not running"));
|
|
if (geteuid() == 0) {
|
|
if (nmbd_running()) {
|
|
nr_running++;
|
|
printf("<td><input type=submit name=\"nmbd_stop\" value=\"%s\"></td>\n", _("Stop nmbd"));
|
|
} else {
|
|
printf("<td><input type=submit name=\"nmbd_start\" value=\"%s\"></td>\n", _("Start nmbd"));
|
|
}
|
|
printf("<td><input type=submit name=\"nmbd_restart\" value=\"%s\"></td>\n", _("Restart nmbd"));
|
|
}
|
|
printf("</tr>\n");
|
|
|
|
#ifdef WITH_WINBIND
|
|
fflush(stdout);
|
|
printf("<tr><td>%s</td><td>%s</td>\n", _("winbindd:"), winbindd_running()?_("running"):_("not running"));
|
|
if (geteuid() == 0) {
|
|
if (winbindd_running()) {
|
|
nr_running++;
|
|
printf("<td><input type=submit name=\"winbindd_stop\" value=\"%s\"></td>\n", _("Stop winbindd"));
|
|
} else {
|
|
printf("<td><input type=submit name=\"winbindd_start\" value=\"%s\"></td>\n", _("Start winbindd"));
|
|
}
|
|
printf("<td><input type=submit name=\"winbindd_restart\" value=\"%s\"></td>\n", _("Restart winbindd"));
|
|
}
|
|
printf("</tr>\n");
|
|
#endif
|
|
|
|
if (geteuid() == 0) {
|
|
printf("<tr><td></td><td></td>\n");
|
|
if (nr_running >= 1) {
|
|
/* stop, restart all */
|
|
printf("<td><input type=submit name=\"all_stop\" value=\"%s\"></td>\n", _("Stop All"));
|
|
printf("<td><input type=submit name=\"all_restart\" value=\"%s\"></td>\n", _("Restart All"));
|
|
}
|
|
else if (nr_running == 0) {
|
|
/* start all */
|
|
printf("<td><input type=submit name=\"all_start\" value=\"%s\"></td>\n", _("Start All"));
|
|
}
|
|
printf("</tr>\n");
|
|
}
|
|
printf("</table>\n");
|
|
fflush(stdout);
|
|
|
|
printf("<p><h3>%s</h3>\n", _("Active Connections"));
|
|
printf("<table border=1>\n");
|
|
printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th>\n", _("PID"), _("Client"), _("IP address"), _("Date"));
|
|
if (geteuid() == 0) {
|
|
printf("<th>%s</th>\n", _("Kill"));
|
|
}
|
|
printf("</tr>\n");
|
|
|
|
connections_forall(traverse_fn2, NULL);
|
|
|
|
printf("</table><p>\n");
|
|
|
|
printf("<p><h3>%s</h3>\n", _("Active Shares"));
|
|
printf("<table border=1>\n");
|
|
printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n\n",
|
|
_("Share"), _("User"), _("Group"), _("PID"), _("Client"), _("Date"));
|
|
|
|
connections_forall(traverse_fn3, NULL);
|
|
|
|
printf("</table><p>\n");
|
|
|
|
printf("<h3>%s</h3>\n", _("Open Files"));
|
|
printf("<table border=1>\n");
|
|
printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n", _("PID"), _("Sharing"), _("R/W"), _("Oplock"), _("File"), _("Date"));
|
|
|
|
locking_init_readonly();
|
|
share_mode_forall(print_share_mode, NULL);
|
|
locking_end();
|
|
printf("</table>\n");
|
|
|
|
printf("<br><input type=submit name=\"show_client_in_col_1\" value=\"%s\">\n", _("Show Client in col 1"));
|
|
printf("<input type=submit name=\"show_pid_in_col_1\" value=\"%s\">\n", _("Show PID in col 1"));
|
|
|
|
printf("</FORM>\n");
|
|
|
|
if (autorefresh) {
|
|
/* this little JavaScript allows for automatic refresh
|
|
of the page. There are other methods but this seems
|
|
to be the best alternative */
|
|
printf("<script language=\"JavaScript\">\n");
|
|
printf("<!--\nsetTimeout('window.location.replace(\"%s/status?refresh_interval=%d&refresh=1\")', %d)\n",
|
|
cgi_baseurl(),
|
|
refresh_interval,
|
|
refresh_interval*1000);
|
|
printf("//-->\n</script>\n");
|
|
}
|
|
TALLOC_FREE(ctx);
|
|
}
|