1 #include "whowatch.h"
2 #include "config.h"
3 #include "ulist.h"
4
5 /* indexes in prot_tab[] */
6 #define SSH 0
7 #define TELNET 1
8 #define LOCAL 2
9
10 static struct prot_t prot_tab[] = {
11 #ifdef HAVE_PROCESS_SYSCTL
12 { "sshd", 22, 0 }, { "telnetd", 23, 0 }, { "init", -1, 0 }
13 #else
14 { "(sshd", 22, 0 }, { "(in.telnetd)", 23, 0 }, { "(init)", -1, 0 }
15 #endif
16 };
17 //static char *hlp = "\001[F1]Help [F9]Menu [ENT]proc all[t]ree [i]dle/cmd [c]md [d]etails [s]ysinfo",
18 static char *hlp = "[ENT]proc all[t]ree [d]etails [s]ysinfo";
19
20 static u32 nusers;
21 static struct wdgt *self;
22
u_count(char * name,int p)23 static void u_count(char *name, int p)
24 {
25 int i;
26 struct prot_t *t;
27 nusers += p;
28 for(i = 0; i < sizeof prot_tab/sizeof(struct prot_t); i++){
29 t = &prot_tab[i];
30 if(strncmp(t->s, name, strlen(t->s))) continue;
31 t->nr += p;
32 }
33 }
34
35 /*
36 * After deleting line, update line numbers in each user structure
37 */
update_line(int line)38 void update_line(int line)
39 {
40 struct user_t *u;
41 struct list_head *tmp;
42 list_for_each(tmp, &users_l) {
43 u = list_entry(tmp, struct user_t, head);
44 if(u->line > line) u->line--;
45 }
46 }
47
48 /*
49 * Create new user structure and fill it
50 */
alloc_user(struct utmpx * entry)51 struct user_t *alloc_user(struct utmpx *entry)
52 {
53 struct user_t *u;
54 int ppid;
55
56 u = calloc(1, sizeof *u);
57 if(!u) errx(1, "Cannot allocate memory.");
58 strncpy(u->name, entry->ut_user, sizeof(entry->ut_user));
59 strncpy(u->tty, entry->ut_line, sizeof(entry->ut_line));
60 strncpy(u->host, entry->ut_host, sizeof(entry->ut_host));
61 u->pid = entry->ut_pid;
62 if((ppid = get_ppid(u->pid)) == -1)
63 strncpy(u->parent, "can't access", sizeof u->parent);
64 else strncpy(u->parent, get_name(ppid), sizeof u->parent - 1);
65 u->line = nusers;
66 return u;
67 }
68
new_user(struct utmpx * ut)69 static struct user_t* new_user(struct utmpx *ut)
70 {
71 struct user_t *u;
72 u = alloc_user(ut);
73 list_add(&u->head, &users_l);
74 u_count(u->parent, LOGIN);
75 return u;
76 }
77
uprint(struct user_t * u,struct wdgt * w)78 static void uprint(struct user_t *u, struct wdgt *w)
79 {
80 int n;
81 scr_attr_set(w, A_BOLD);
82 n = snprintf(w->mwin->gbuf, w->mwin->gbsize, "%-14.14s %-9.9s %-6.6s %-19.19s %s",
83 u->parent, u->name, u->tty, u->host,
84 toggle?count_idle(u->tty):get_w(u->pid));
85 scr_maddstr(w, w->mwin->gbuf, u->line, 0, n);
86 }
87
uredraw(struct wdgt * w)88 void uredraw(struct wdgt *w)
89 {
90 struct list_head *tmp;
91 struct user_t *u;
92 scr_werase(w);
93 scr_output_start(w);
94 list_for_each_r(tmp, &users_l) {
95 u = list_entry(tmp, struct user_t, head);
96 uprint(u, w);
97 }
98 scr_output_end(w);
99 }
100
101 /*
102 * Gather information about users currently on the machine
103 * Called only at start or restart
104 */
read_utmp(void)105 void read_utmp(void)
106 {
107 static struct utmpx *entry;
108 struct user_t *u;
109
110 while ((entry = getutxent()) != NULL) {
111 if(entry->ut_type != USER_PROCESS) continue;
112 u = new_user(entry);
113 }
114 return;
115 }
116
117 /*
118 * get user entry from specific line (cursor position)
119 */
cursor_user(int line)120 struct user_t *cursor_user(int line)
121 {
122 struct user_t *u;
123 struct list_head *h;
124 DBG("looking for user on line %d", line);
125 // int line = 0; //current->cursor + current->offset;
126 list_for_each(h, &users_l) {
127 u = list_entry(h, struct user_t, head);
128 if(u->line == line) return u;
129 }
130 return 0;
131 }
132
udel(struct user_t * u,struct wdgt * w)133 static void udel(struct user_t *u, struct wdgt *w)
134 {
135 scr_delline(w, u->line);
136 scr_ldeleted(w, u->line);
137 update_line(u->line);
138 u_count(u->parent, LOGOUT);
139 list_del(&u->head);
140 free(u);
141 }
142
proc_ucount(void)143 char *proc_ucount(void)
144 {
145 static char buf[64];
146
147 int other = nusers - prot_tab[LOCAL].nr - prot_tab[TELNET].nr - prot_tab[SSH].nr;
148 snprintf(buf, sizeof buf - 1,"\x1%d users: %d local, %d telnet, %d ssh, %d other\x3",
149 nusers, prot_tab[LOCAL].nr, prot_tab[TELNET].nr, prot_tab[SSH].nr, other);
150 return buf;
151 }
152
open_wtmp(int * wtmp_fd)153 static void open_wtmp(int *wtmp_fd)
154 {
155 if((*wtmp_fd = open(WTMP_FILE ,O_RDONLY)) == -1) err_exit(1, "Cannot open wtmp");
156 if(lseek(*wtmp_fd, 0, SEEK_END) == -1) err_exit(1, "Cannot seek end wtmp");
157 }
158
159 /*
160 * Check wtmp for logouts or new logins
161 */
check_wtmp(struct wdgt * w)162 static void check_wtmp(struct wdgt *w)
163 {
164 static int wtmp_fd;
165 struct user_t *u;
166 struct list_head *h;
167 struct utmpx entry;
168 int i, changed = 0;
169 if(!wtmp_fd) open_wtmp(&wtmp_fd);
170
171 while((i = read(wtmp_fd, &entry, sizeof entry)) > 0){
172 if (i < sizeof entry) prg_exit("Error reading wtmp");
173 /* user just logged in */
174 if(entry.ut_type == USER_PROCESS) {
175 u = new_user(&entry);
176 changed = 1;
177 continue;
178 }
179 if(entry.ut_type != DEAD_PROCESS) continue;
180 /* user just logged out */
181 list_for_each(h, &users_l) {
182 u = list_entry(h, struct user_t, head);
183 if(strncmp(u->tty, entry.ut_line, sizeof(entry.ut_line)))
184 continue;
185 udel(u, w);
186 changed = 1;
187 break;
188 }
189 }
190 if(!changed) return;
191 }
192
ulist_hlp(struct wdgt * w)193 static void ulist_hlp(struct wdgt *w)
194 {
195 DBG("sending %s", hlp);
196 wmsg_send(w, MCUR_HLP, hlp);
197 }
198
users_init(void)199 void users_init(void)
200 {
201 read_utmp();
202 }
203
ulist_periodic(struct wdgt * w)204 static void ulist_periodic(struct wdgt *w)
205 {
206 static int i;
207
208 if(!i) {
209 wmsg_send(w, MCUR_HLP, hlp);
210 i = 1;
211 }
212 DBG("ulist periodic");
213 check_wtmp(w);
214 }
215
cval(void)216 static void *cval(void)
217 {
218 static struct user_t *u;
219
220 u = cursor_user(self->crsr);
221 if(u) return &u->pid;
222 return 0;
223 }
224
225 /*
226 * Needed for search function. If parent, name, tty, host or command line
227 * matches then returns line number of this user.
228 */
user_search(struct wdgt * w,int t)229 static int user_search(struct wdgt *w, int t)
230 {
231 struct user_t *u;
232 struct list_head *h;
233 int l = w->crsr;
234
235 list_for_each(h, &users_l) {
236 u = list_entry(h, struct user_t, head);
237 if(!t && u->line <= l) continue;
238 if(t == 1 && u->line < l) continue;
239 if(reg_match(u->parent)) goto found;
240 if(reg_match(u->name)) goto found;
241 if(reg_match(u->tty)) goto found;
242 if(reg_match(u->host)) goto found;
243 if(reg_match(toggle?count_idle(u->tty):get_w(u->pid)))
244 goto found;
245 }
246 return 2;
247 found:
248 scr_crsr_jmp(w, u->line);
249 return 1;
250 }
251
umsgh(struct wdgt * w,int type,struct wdgt * s,void * d)252 static void *umsgh(struct wdgt *w, int type, struct wdgt *s, void *d)
253 {
254 struct user_t *u;
255 /* accept it even not visible, ptree can ask about user pid*/
256 if(type == MWANT_UPID) {
257 u = cursor_user(w->crsr);
258 if(u) return &u->pid;
259 else return 0;
260 }
261 if(WIN_HIDDEN(w)) return 0;
262 DBG("ulist responded to type %d", type);
263 switch(type) {
264 case MALL_CRSR_REG: w->flags |= WDGT_CRSR_SND; break;
265 case MALL_CRSR_UNREG: w->flags &= ~ WDGT_CRSR_SND; break;
266 case MWANT_CRSR_VAL: u = cursor_user(w->crsr);
267 if(u) return u->name;
268 else return "No user found";
269 case MSND_SEARCH:
270 return (void *)(intptr_t)user_search(w, (u32)d);
271 break;
272 }
273
274 return 0;
275 }
276
277 /*
278 * Give up main window if currently printing output there
279 * or start printing if not there
280 */
uswitch(struct wdgt * w,int k,int p)281 static void uswitch(struct wdgt *w, int k, int p)
282 {
283 if(!WIN_HIDDEN(w)) {
284 DBG("Deleting ulist from lists");
285 w->redraw = 0;
286 w->wrefresh = 0;
287 }
288 else {
289 if(k == 't') return;
290 ulist_hlp(w);
291 w->redraw = uredraw;
292 w->wrefresh = scr_wrefresh;
293 WNEED_REDRAW(w);
294 wmsg_send(w, MSND_ESOURCE, euser);
295 }
296 }
297
crsr_send(struct wdgt * w)298 static void crsr_send(struct wdgt *w)
299 {
300 struct user_t *u;
301
302 if(!(w->flags & WDGT_CRSR_SND)) return;
303 u = cursor_user(w->crsr);
304 if(!u) return;
305 DBG("sending current name %s", u->name);
306 wmsg_send(w, MCUR_CRSR, u->name);
307 }
308
309
ukeyh(struct wdgt * w,int key)310 static int ukeyh(struct wdgt *w, int key)
311 {
312 int ret = KEY_SKIPPED;
313 static int pkey;
314
315 /* hide/unhide widget */
316 if(key == 't' || key == KBD_ENTER) {
317 uswitch(w, key, pkey);
318 pkey = key;
319 return KEY_HANDLED;
320 }
321 if(WIN_HIDDEN(w)) return ret;
322 switch(key) {
323 default:
324 ret = scr_keyh(w, key);
325 if(ret == KEY_HANDLED) crsr_send(w);
326 }
327 return ret;
328 }
329
ulist_reg(struct wdgt * w)330 void ulist_reg(struct wdgt *w)
331 {
332 w->periodic = ulist_periodic;
333 w->redraw = uredraw;
334 w->wrefresh = scr_wrefresh;
335 w->keyh = ukeyh;
336 w->msgh = umsgh;
337 w->mwin->cval = cval;
338 mwin_msg_on(w);
339 self = w;
340 }
341
342