| File: | src/usr.bin/rusers/rusers.c |
| Warning: | line 610, column 12 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rusers.c,v 1.43 2020/12/29 19:52:16 benno Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2001, 2003 Todd C. Miller <millert@openbsd.org> | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 17 | * Sponsored in part by the Defense Advanced Research Projects | |||
| 18 | * Agency (DARPA) and Air Force Research Laboratory, Air Force | |||
| 19 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. | |||
| 20 | */ | |||
| 21 | /*- | |||
| 22 | * Copyright (c) 1993 John Brezak | |||
| 23 | * All rights reserved. | |||
| 24 | * | |||
| 25 | * Redistribution and use in source and binary forms, with or without | |||
| 26 | * modification, are permitted provided that the following conditions | |||
| 27 | * are met: | |||
| 28 | * 1. Redistributions of source code must retain the above copyright | |||
| 29 | * notice, this list of conditions and the following disclaimer. | |||
| 30 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 31 | * notice, this list of conditions and the following disclaimer in the | |||
| 32 | * documentation and/or other materials provided with the distribution. | |||
| 33 | * 3. The name of the author may not be used to endorse or promote products | |||
| 34 | * derived from this software without specific prior written permission. | |||
| 35 | * | |||
| 36 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | |||
| 37 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| 38 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| 39 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |||
| 40 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| 41 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
| 42 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
| 44 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |||
| 45 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 46 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 47 | */ | |||
| 48 | ||||
| 49 | #include <sys/ioctl.h> | |||
| 50 | #include <sys/socket.h> | |||
| 51 | #include <sys/signal.h> | |||
| 52 | #include <rpc/rpc.h> | |||
| 53 | #include <rpc/pmap_prot.h> | |||
| 54 | #include <rpc/pmap_rmt.h> | |||
| 55 | #include <rpcsvc/rusers.h> | |||
| 56 | #include <rpcsvc/rnusers.h> /* Old protocol version */ | |||
| 57 | #include <arpa/inet.h> | |||
| 58 | #include <net/if.h> | |||
| 59 | #include <err.h> | |||
| 60 | #include <errno(*__errno()).h> | |||
| 61 | #include <ifaddrs.h> | |||
| 62 | #include <netdb.h> | |||
| 63 | #include <stdio.h> | |||
| 64 | #include <stdlib.h> | |||
| 65 | #include <string.h> | |||
| 66 | #include <termios.h> | |||
| 67 | #include <unistd.h> | |||
| 68 | #include <limits.h> | |||
| 69 | #include <poll.h> | |||
| 70 | ||||
| 71 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) | |||
| 72 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
| 73 | ||||
| 74 | /* Preferred formatting */ | |||
| 75 | #define HOST_WIDTH17 17 | |||
| 76 | #define LINE_WIDTH8 8 | |||
| 77 | #define NAME_WIDTH8 8 | |||
| 78 | ||||
| 79 | #define MAX_BROADCAST_SIZE1400 1400 | |||
| 80 | ||||
| 81 | struct host_info { | |||
| 82 | u_int count; | |||
| 83 | u_int idle; | |||
| 84 | char *host; | |||
| 85 | rusers_utmp *users; | |||
| 86 | } *hostinfo; | |||
| 87 | ||||
| 88 | void print_entry(struct host_info *, int); | |||
| 89 | void fmt_idle(int, char *, size_t); | |||
| 90 | void onehost(char *); | |||
| 91 | void allhosts(void); | |||
| 92 | void sorthosts(void); | |||
| 93 | void expandhosts(void); | |||
| 94 | void alarmclock(int); | |||
| 95 | char *estrndup(const char *, size_t); | |||
| 96 | struct host_info *add_host(char *); | |||
| 97 | int hcompare(const void *, const void *); | |||
| 98 | int icompare(const void *, const void *); | |||
| 99 | int ucompare(const void *, const void *); | |||
| 100 | bool_tint32_t rusers_reply(char *, struct sockaddr_in *); | |||
| 101 | bool_tint32_t rusers_reply_3(char *, struct sockaddr_in *); | |||
| 102 | enum clnt_stat get_reply(int, in_port_t, u_long, struct rpc_msg *, | |||
| 103 | struct rmtcallres *, bool_tint32_t (*)(char *, struct sockaddr_in *)); | |||
| 104 | enum clnt_stat rpc_setup(int *, XDR *, struct rpc_msg *, | |||
| 105 | struct rmtcallargs *, AUTH *, char *); | |||
| 106 | __dead__attribute__((__noreturn__)) void usage(void); | |||
| 107 | ||||
| 108 | int aflag, hflag, iflag, lflag, uflag; | |||
| 109 | u_int nentries, maxentries; | |||
| 110 | long termwidth; | |||
| 111 | extern char *__progname; | |||
| 112 | ||||
| 113 | int | |||
| 114 | main(int argc, char **argv) | |||
| 115 | { | |||
| 116 | struct winsize win; | |||
| 117 | char *cp; | |||
| 118 | int ch; | |||
| 119 | ||||
| 120 | while ((ch = getopt(argc, argv, "ahilu")) != -1) | |||
| ||||
| 121 | switch (ch) { | |||
| 122 | case 'a': | |||
| 123 | aflag = 1; | |||
| 124 | break; | |||
| 125 | case 'h': | |||
| 126 | hflag = 1; | |||
| 127 | break; | |||
| 128 | case 'i': | |||
| 129 | iflag = 1; | |||
| 130 | break; | |||
| 131 | case 'l': | |||
| 132 | lflag = 1; | |||
| 133 | break; | |||
| 134 | case 'u': | |||
| 135 | uflag = 1; | |||
| 136 | break; | |||
| 137 | default: | |||
| 138 | usage(); | |||
| 139 | /*NOTREACHED*/ | |||
| 140 | } | |||
| 141 | ||||
| 142 | if (hflag + iflag + uflag > 1) | |||
| 143 | usage(); | |||
| 144 | ||||
| 145 | termwidth = 0; | |||
| 146 | if ((cp = getenv("COLUMNS")) != NULL((void *)0)) | |||
| 147 | termwidth = strtonum(cp, 1, LONG_MAX9223372036854775807L, NULL((void *)0)); | |||
| 148 | if (termwidth == 0 && ioctl(STDOUT_FILENO1, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff ) << 16) | ((('t')) << 8) | ((104))), &win) == 0 && | |||
| 149 | win.ws_col > 0) | |||
| 150 | termwidth = win.ws_col; | |||
| 151 | if (termwidth
| |||
| 152 | termwidth = 80; | |||
| 153 | ||||
| 154 | setvbuf(stdout(&__sF[1]), NULL((void *)0), _IOLBF1, 0); | |||
| 155 | ||||
| 156 | if (argc == optind) { | |||
| 157 | if (hflag || iflag || uflag) { | |||
| 158 | puts("Collecting responses..."); | |||
| 159 | allhosts(); | |||
| 160 | sorthosts(); | |||
| 161 | } else | |||
| 162 | allhosts(); | |||
| 163 | } else { | |||
| 164 | aflag = 1; | |||
| 165 | for (; optind < argc; optind++) | |||
| 166 | (void) onehost(argv[optind]); | |||
| 167 | if (hflag || iflag || uflag) | |||
| 168 | sorthosts(); | |||
| 169 | } | |||
| 170 | ||||
| 171 | exit(0); | |||
| 172 | } | |||
| 173 | ||||
| 174 | struct host_info * | |||
| 175 | add_host(char *host) | |||
| 176 | { | |||
| 177 | int i; | |||
| 178 | ||||
| 179 | for (i = 0; i < nentries; i++) { | |||
| 180 | /* Existing entry. */ | |||
| 181 | if (strcmp(host, hostinfo[i].host) == 0) | |||
| 182 | return(NULL((void *)0)); | |||
| 183 | } | |||
| 184 | ||||
| 185 | /* New entry, allocate space if needed and store. */ | |||
| 186 | if (nentries == maxentries) { | |||
| 187 | maxentries += 128; | |||
| 188 | hostinfo = reallocarray(hostinfo, maxentries, | |||
| 189 | sizeof(*hostinfo)); | |||
| 190 | if (hostinfo == NULL((void *)0)) | |||
| 191 | err(1, NULL((void *)0)); | |||
| 192 | } | |||
| 193 | if ((hostinfo[nentries].host = strdup(host)) == NULL((void *)0)) | |||
| 194 | err(1, NULL((void *)0)); | |||
| 195 | return(&hostinfo[nentries++]); | |||
| 196 | } | |||
| 197 | ||||
| 198 | void | |||
| 199 | fmt_idle(int idle, char *idle_time, size_t idle_time_len) | |||
| 200 | { | |||
| 201 | int days, hours, minutes, seconds; | |||
| 202 | ||||
| 203 | switch (idle) { | |||
| 204 | case 0: | |||
| 205 | *idle_time = '\0'; | |||
| 206 | break; | |||
| 207 | case INT_MAX2147483647: | |||
| 208 | strlcpy(idle_time, "??", idle_time_len); | |||
| 209 | break; | |||
| 210 | default: | |||
| 211 | seconds = idle; | |||
| 212 | days = seconds / (60*60*24); | |||
| 213 | seconds %= (60*60*24); | |||
| 214 | hours = seconds / (60*60); | |||
| 215 | seconds %= (60*60); | |||
| 216 | minutes = seconds / 60; | |||
| 217 | seconds %= 60; | |||
| 218 | if (idle >= (24*60*60)) | |||
| 219 | snprintf(idle_time, idle_time_len, | |||
| 220 | "%d day%s, %d:%02d:%02d", days, | |||
| 221 | days > 1 ? "s" : "", hours, minutes, seconds); | |||
| 222 | else if (idle >= (60*60)) | |||
| 223 | snprintf(idle_time, idle_time_len, "%2d:%02d:%02d", | |||
| 224 | hours, minutes, seconds); | |||
| 225 | else if (idle > 60) | |||
| 226 | snprintf(idle_time, idle_time_len, "%2d:%02d", | |||
| 227 | minutes, seconds); | |||
| 228 | else | |||
| 229 | snprintf(idle_time, idle_time_len, " :%02d", idle); | |||
| 230 | break; | |||
| 231 | } | |||
| 232 | } | |||
| 233 | ||||
| 234 | bool_tint32_t | |||
| 235 | rusers_reply(char *replyp, struct sockaddr_in *raddrp) | |||
| 236 | { | |||
| 237 | utmpidlearr *up = (utmpidlearr *)replyp; | |||
| 238 | struct host_info *entry; | |||
| 239 | struct hostent *hp; | |||
| 240 | rusers_utmp *ut; | |||
| 241 | char *host; | |||
| 242 | int i; | |||
| 243 | ||||
| 244 | if (!aflag && up->uia_cnt == 0) | |||
| 245 | return(0); | |||
| 246 | ||||
| 247 | hp = gethostbyaddr((char *)&raddrp->sin_addr, | |||
| 248 | sizeof(struct in_addr), AF_INET2); | |||
| 249 | if (hp) | |||
| 250 | host = hp->h_name; | |||
| 251 | else | |||
| 252 | host = inet_ntoa(raddrp->sin_addr); | |||
| 253 | if ((entry = add_host(host)) == NULL((void *)0)) | |||
| 254 | return(0); | |||
| 255 | ||||
| 256 | if (up->uia_cnt == 0) | |||
| 257 | ut = NULL((void *)0); | |||
| 258 | else if ((ut = calloc(up->uia_cnt, sizeof(*ut))) == NULL((void *)0)) | |||
| 259 | err(1, NULL((void *)0)); | |||
| 260 | entry->users = ut; | |||
| 261 | entry->count = up->uia_cnt; | |||
| 262 | entry->idle = UINT_MAX(2147483647 *2U +1U); | |||
| 263 | for (i = 0; i < up->uia_cnt; i++, ut++) { | |||
| 264 | ut->ut_user = estrndup(up->uia_arr[i]->ui_utmp.ut_name, | |||
| 265 | RNUSERS_MAXUSERLEN8); | |||
| 266 | ut->ut_line = estrndup(up->uia_arr[i]->ui_utmp.ut_line, | |||
| 267 | RNUSERS_MAXLINELEN8); | |||
| 268 | ut->ut_host = estrndup(up->uia_arr[i]->ui_utmp.ut_host, | |||
| 269 | RNUSERS_MAXHOSTLEN16); | |||
| 270 | ut->ut_time = up->uia_arr[i]->ui_utmp.ut_time; | |||
| 271 | ut->ut_idle = up->uia_arr[i]->ui_idle; | |||
| 272 | if (ut->ut_idle < entry->idle) | |||
| 273 | entry->idle = ut->ut_idle; | |||
| 274 | } | |||
| 275 | ||||
| 276 | if (!hflag && !iflag && !uflag) { | |||
| 277 | print_entry(entry, lflag && entry->count); | |||
| 278 | for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { | |||
| 279 | free(ut->ut_user); | |||
| 280 | free(ut->ut_line); | |||
| 281 | free(ut->ut_host); | |||
| 282 | } | |||
| 283 | free(entry->users); | |||
| 284 | } | |||
| 285 | ||||
| 286 | return(0); | |||
| 287 | } | |||
| 288 | ||||
| 289 | bool_tint32_t | |||
| 290 | rusers_reply_3(char *replyp, struct sockaddr_in *raddrp) | |||
| 291 | { | |||
| 292 | utmp_array *up3 = (utmp_array *)replyp; | |||
| 293 | struct host_info *entry; | |||
| 294 | struct hostent *hp; | |||
| 295 | rusers_utmp *ut; | |||
| 296 | char *host; | |||
| 297 | int i; | |||
| 298 | ||||
| 299 | if (!aflag && up3->utmp_array_len == 0) | |||
| 300 | return(0); | |||
| 301 | ||||
| 302 | hp = gethostbyaddr((char *)&raddrp->sin_addr, | |||
| 303 | sizeof(struct in_addr), AF_INET2); | |||
| 304 | if (hp) | |||
| 305 | host = hp->h_name; | |||
| 306 | else | |||
| 307 | host = inet_ntoa(raddrp->sin_addr); | |||
| 308 | if ((entry = add_host(host)) == NULL((void *)0)) | |||
| 309 | return(0); | |||
| 310 | ||||
| 311 | if (up3->utmp_array_len == 0) | |||
| 312 | ut = NULL((void *)0); | |||
| 313 | else if ((ut = calloc(up3->utmp_array_len, sizeof(*ut))) == NULL((void *)0)) | |||
| 314 | err(1, NULL((void *)0)); | |||
| 315 | entry->users = ut; | |||
| 316 | entry->count = up3->utmp_array_len; | |||
| 317 | entry->idle = UINT_MAX(2147483647 *2U +1U); | |||
| 318 | for (i = 0; i < up3->utmp_array_len; i++, ut++) { | |||
| 319 | ut->ut_user = estrndup(up3->utmp_array_val[i].ut_user, | |||
| 320 | RUSERS_MAXUSERLEN32); | |||
| 321 | ut->ut_line = estrndup(up3->utmp_array_val[i].ut_line, | |||
| 322 | RUSERS_MAXLINELEN32); | |||
| 323 | ut->ut_host = estrndup(up3->utmp_array_val[i].ut_host, | |||
| 324 | RUSERS_MAXHOSTLEN257); | |||
| 325 | ut->ut_time = up3->utmp_array_val[i].ut_time; | |||
| 326 | ut->ut_idle = up3->utmp_array_val[i].ut_idle; | |||
| 327 | if (ut->ut_idle < entry->idle) | |||
| 328 | entry->idle = ut->ut_idle; | |||
| 329 | } | |||
| 330 | ||||
| 331 | if (!hflag && !iflag && !uflag) { | |||
| 332 | print_entry(entry, lflag && entry->count); | |||
| 333 | for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { | |||
| 334 | free(ut->ut_user); | |||
| 335 | free(ut->ut_line); | |||
| 336 | free(ut->ut_host); | |||
| 337 | } | |||
| 338 | free(entry->users); | |||
| 339 | } | |||
| 340 | ||||
| 341 | return(0); | |||
| 342 | } | |||
| 343 | ||||
| 344 | void | |||
| 345 | onehost(char *host) | |||
| 346 | { | |||
| 347 | utmpidlearr up; | |||
| 348 | utmp_array up3; | |||
| 349 | CLIENT *rusers_clnt; | |||
| 350 | struct sockaddr_in sin; | |||
| 351 | struct hostent *hp; | |||
| 352 | struct timeval tv = { 25, 0 }; | |||
| 353 | int error; | |||
| 354 | ||||
| 355 | memset(&sin, 0, sizeof sin); | |||
| 356 | ||||
| 357 | hp = gethostbyname(host); | |||
| 358 | if (hp == NULL((void *)0)) | |||
| 359 | errx(1, "unknown host \"%s\"", host); | |||
| 360 | ||||
| 361 | /* Try version 3 first. */ | |||
| 362 | rusers_clnt = clnt_create(host, RUSERSPROG((u_long)100002), RUSERSVERS_3((u_long)3), "udp"); | |||
| 363 | if (rusers_clnt == NULL((void *)0)) { | |||
| 364 | clnt_pcreateerror(__progname); | |||
| 365 | exit(1); | |||
| 366 | } | |||
| 367 | ||||
| 368 | memset(&up3, 0, sizeof(up3)); | |||
| 369 | error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmp_array, (caddr_t )&up3, tv)) | |||
| 370 | xdr_utmp_array, &up3, tv)((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmp_array, (caddr_t )&up3, tv)); | |||
| 371 | switch (error) { | |||
| 372 | case RPC_SUCCESS: | |||
| 373 | sin.sin_addr.s_addr = *(int *)hp->h_addrh_addr_list[0]; | |||
| 374 | rusers_reply_3((char *)&up3, &sin); | |||
| 375 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
| 376 | return; | |||
| 377 | case RPC_PROGVERSMISMATCH: | |||
| 378 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
| 379 | break; | |||
| 380 | default: | |||
| 381 | clnt_perror(rusers_clnt, __progname); | |||
| 382 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
| 383 | exit(1); | |||
| 384 | } | |||
| 385 | ||||
| 386 | /* Fall back to version 2. */ | |||
| 387 | rusers_clnt = clnt_create(host, RUSERSPROG((u_long)100002), RUSERSVERS_IDLE2, "udp"); | |||
| 388 | if (rusers_clnt == NULL((void *)0)) { | |||
| 389 | clnt_pcreateerror(__progname); | |||
| 390 | exit(1); | |||
| 391 | } | |||
| 392 | ||||
| 393 | memset(&up, 0, sizeof(up)); | |||
| 394 | error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL,((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmpidlearr, (caddr_t )&up, tv)) | |||
| 395 | xdr_utmpidlearr, &up, tv)((*(rusers_clnt)->cl_ops->cl_call)(rusers_clnt, ((u_long )2), xdr_void, (caddr_t)((void *)0), xdr_utmpidlearr, (caddr_t )&up, tv)); | |||
| 396 | if (error != RPC_SUCCESS) { | |||
| 397 | clnt_perror(rusers_clnt, __progname); | |||
| 398 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
| 399 | exit(1); | |||
| 400 | } | |||
| 401 | sin.sin_addr.s_addr = *(int *)hp->h_addrh_addr_list[0]; | |||
| 402 | rusers_reply((char *)&up, &sin); | |||
| 403 | clnt_destroy(rusers_clnt)((*(rusers_clnt)->cl_ops->cl_destroy)(rusers_clnt)); | |||
| 404 | } | |||
| 405 | ||||
| 406 | enum clnt_stat | |||
| 407 | get_reply(int sock, in_port_t port, u_long xid, struct rpc_msg *msgp, | |||
| 408 | struct rmtcallres *resp, bool_tint32_t (*callback)(char *, struct sockaddr_in *)) | |||
| 409 | { | |||
| 410 | ssize_t inlen; | |||
| 411 | socklen_t fromlen; | |||
| 412 | struct sockaddr_in raddr; | |||
| 413 | char inbuf[UDPMSGSIZE8800]; | |||
| 414 | XDR xdr; | |||
| 415 | ||||
| 416 | retry: | |||
| 417 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
| 418 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = (caddr_t)resp; | |||
| 419 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_rmtcallres; | |||
| 420 | ||||
| 421 | fromlen = sizeof(raddr); | |||
| 422 | inlen = recvfrom(sock, inbuf, sizeof(inbuf), 0, | |||
| 423 | (struct sockaddr *)&raddr, &fromlen); | |||
| 424 | if (inlen == -1) { | |||
| 425 | if (errno(*__errno()) == EINTR4) | |||
| 426 | goto retry; | |||
| 427 | return (RPC_CANTRECV); | |||
| 428 | } | |||
| 429 | if (inlen < sizeof(u_int32_t)) | |||
| 430 | goto retry; | |||
| 431 | ||||
| 432 | /* | |||
| 433 | * If the reply we got matches our request, decode the | |||
| 434 | * replay and pass it to the callback function. | |||
| 435 | */ | |||
| 436 | xdrmem_create(&xdr, inbuf, (u_int)inlen, XDR_DECODE); | |||
| 437 | if (xdr_replymsg(&xdr, msgp)) { | |||
| 438 | if ((msgp->rm_xid == xid) && | |||
| 439 | (msgp->rm_replyru.RM_rmb.rp_stat == MSG_ACCEPTED) && | |||
| 440 | (msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_stat == SUCCESS)) { | |||
| 441 | raddr.sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t )(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U ) >> 8) : __swap16md(port)); | |||
| 442 | (void)(*callback)(resp->results_ptr, &raddr); | |||
| 443 | } | |||
| 444 | } | |||
| 445 | xdr.x_op = XDR_FREE; | |||
| 446 | msgp->acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
| 447 | (void)xdr_replymsg(&xdr, msgp); | |||
| 448 | (void)(*resp->xdr_results)(&xdr, resp->results_ptr); | |||
| 449 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
| 450 | ||||
| 451 | return(RPC_SUCCESS); | |||
| 452 | } | |||
| 453 | ||||
| 454 | enum clnt_stat | |||
| 455 | rpc_setup(int *fdp, XDR *xdr, struct rpc_msg *msg, struct rmtcallargs *args, | |||
| 456 | AUTH *unix_auth, char *buf) | |||
| 457 | { | |||
| 458 | int on = 1; | |||
| 459 | ||||
| 460 | if ((*fdp = socket(AF_INET2, SOCK_DGRAM2, IPPROTO_UDP17)) == -1) | |||
| 461 | return(RPC_CANTSEND); | |||
| 462 | ||||
| 463 | if (setsockopt(*fdp, SOL_SOCKET0xffff, SO_BROADCAST0x0020, &on, sizeof(on)) == -1) | |||
| 464 | return(RPC_CANTSEND); | |||
| 465 | ||||
| 466 | msg->rm_xid = arc4random(); | |||
| 467 | msg->rm_direction = CALL; | |||
| 468 | msg->rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
| 469 | msg->rm_callru.RM_cmb.cb_prog = PMAPPROG((unsigned long)100000); | |||
| 470 | msg->rm_callru.RM_cmb.cb_vers = PMAPVERS((unsigned long)2); | |||
| 471 | msg->rm_callru.RM_cmb.cb_proc = PMAPPROC_CALLIT((unsigned long)5); | |||
| 472 | msg->rm_callru.RM_cmb.cb_cred = unix_auth->ah_cred; | |||
| 473 | msg->rm_callru.RM_cmb.cb_verf = unix_auth->ah_verf; | |||
| 474 | ||||
| 475 | xdrmem_create(xdr, buf, MAX_BROADCAST_SIZE1400, XDR_ENCODE); | |||
| 476 | if (!xdr_callmsg(xdr, msg) || !xdr_rmtcall_args(xdr, args)) | |||
| 477 | return(RPC_CANTENCODEARGS); | |||
| 478 | ||||
| 479 | return(RPC_SUCCESS); | |||
| 480 | } | |||
| 481 | ||||
| 482 | void | |||
| 483 | allhosts(void) | |||
| 484 | { | |||
| 485 | enum clnt_stat stat; | |||
| 486 | struct itimerval timeout; | |||
| 487 | AUTH *unix_auth; | |||
| 488 | size_t outlen[2]; | |||
| 489 | int sock[2] = { -1, -1 }; | |||
| 490 | int i, rval; | |||
| 491 | u_long xid[2], port[2]; | |||
| 492 | struct pollfd pfd[2]; | |||
| 493 | struct sockaddr_in *sin, baddr; | |||
| 494 | struct rmtcallargs args; | |||
| 495 | struct rmtcallres res[2]; | |||
| 496 | struct rpc_msg msg[2]; | |||
| 497 | struct ifaddrs *ifa, *ifap = NULL((void *)0); | |||
| 498 | char buf[2][MAX_BROADCAST_SIZE1400]; | |||
| 499 | utmpidlearr up; | |||
| 500 | utmp_array up3; | |||
| 501 | XDR xdr; | |||
| 502 | ||||
| 503 | if ((unix_auth = authunix_create_default()) == NULL((void *)0)) | |||
| 504 | err(1, "can't create auth handle"); | |||
| 505 | ||||
| 506 | if (getifaddrs(&ifap) != 0) | |||
| 507 | err(1, "can't get list of interface addresses"); | |||
| 508 | ||||
| 509 | memset(&up, 0, sizeof(up)); | |||
| 510 | memset(&up3, 0, sizeof(up3)); | |||
| 511 | memset(&baddr, 0, sizeof(baddr)); | |||
| 512 | memset(&res, 0, sizeof(res)); | |||
| 513 | memset(&msg, 0, sizeof(msg)); | |||
| 514 | memset(&timeout, 0, sizeof(timeout)); | |||
| 515 | ||||
| 516 | args.prog = RUSERSPROG((u_long)100002); | |||
| 517 | args.vers = RUSERSVERS_IDLE2; | |||
| 518 | args.proc = RUSERSPROC_NAMES((u_long)2); | |||
| 519 | args.xdr_args = xdr_void; | |||
| 520 | args.args_ptr = NULL((void *)0); | |||
| 521 | ||||
| 522 | stat = rpc_setup(&sock[0], &xdr, &msg[0], &args, unix_auth, buf[0]); | |||
| 523 | if (stat
| |||
| 524 | goto cleanup; | |||
| 525 | xid[0] = msg[0].rm_xid; | |||
| 526 | outlen[0] = xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
| 527 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
| 528 | ||||
| 529 | args.vers = RUSERSVERS_3((u_long)3); | |||
| 530 | stat = rpc_setup(&sock[1], &xdr, &msg[1], &args, unix_auth, buf[1]); | |||
| 531 | if (stat
| |||
| 532 | goto cleanup; | |||
| 533 | xid[1] = msg[1].rm_xid; | |||
| 534 | outlen[1] = xdr_getpos(&xdr)(*(&xdr)->x_ops->x_getpostn)(&xdr); | |||
| 535 | xdr_destroy(&xdr)if ((&xdr)->x_ops->x_destroy) (*(&xdr)->x_ops ->x_destroy)(&xdr); | |||
| 536 | ||||
| 537 | baddr.sin_family = AF_INET2; | |||
| 538 | baddr.sin_port = htons(PMAPPORT)(__uint16_t)(__builtin_constant_p(((unsigned short)111)) ? (__uint16_t )(((__uint16_t)(((unsigned short)111)) & 0xffU) << 8 | ((__uint16_t)(((unsigned short)111)) & 0xff00U) >> 8) : __swap16md(((unsigned short)111))); | |||
| 539 | baddr.sin_addr.s_addr = htonl(INADDR_ANY)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x00000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x00000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x00000000)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x00000000 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x00000000)))); | |||
| 540 | ||||
| 541 | res[0].port_ptr = &port[0]; | |||
| 542 | res[0].xdr_results = xdr_utmpidlearr; | |||
| 543 | res[0].results_ptr = (caddr_t)&up; | |||
| 544 | ||||
| 545 | res[1].port_ptr = &port[1]; | |||
| 546 | res[1].xdr_results = xdr_utmp_array; | |||
| 547 | res[1].results_ptr = (caddr_t)&up3; | |||
| 548 | ||||
| 549 | (void)signal(SIGALRM14, alarmclock); | |||
| 550 | ||||
| 551 | /* | |||
| 552 | * We do 6 runs through the loop. On even runs we send | |||
| 553 | * a version 3 broadcast. On odd ones we send a version 2 | |||
| 554 | * broadcast. This should give version 3 replies enough | |||
| 555 | * of an 'edge' over the old version 2 ones in most cases. | |||
| 556 | * We poll() waiting for replies for 5 seconds in between | |||
| 557 | * each broadcast. | |||
| 558 | */ | |||
| 559 | for (i = 0; i < 6; i++) { | |||
| 560 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | |||
| 561 | if (ifa->ifa_addr == NULL((void *)0) || | |||
| 562 | ifa->ifa_addr->sa_family != AF_INET2 || | |||
| 563 | !(ifa->ifa_flags & IFF_BROADCAST0x2) || | |||
| 564 | !(ifa->ifa_flags & IFF_UP0x1) || | |||
| 565 | ifa->ifa_broadaddrifa_dstaddr == NULL((void *)0) || | |||
| 566 | ifa->ifa_broadaddrifa_dstaddr->sa_family != AF_INET2) | |||
| 567 | continue; | |||
| 568 | sin = (struct sockaddr_in *)ifa->ifa_broadaddrifa_dstaddr; | |||
| 569 | baddr.sin_addr = sin->sin_addr; | |||
| 570 | ||||
| 571 | /* use protocol 2 or 3 depending on i (odd or even) */ | |||
| 572 | if (i & 1) { | |||
| 573 | if (sendto(sock[0], buf[0], outlen[0], 0, | |||
| 574 | (struct sockaddr *)&baddr, | |||
| 575 | sizeof(baddr)) != outlen[0]) | |||
| 576 | err(1, "can't send broadcast packet"); | |||
| 577 | } else { | |||
| 578 | if (sendto(sock[1], buf[1], outlen[1], 0, | |||
| 579 | (struct sockaddr *)&baddr, | |||
| 580 | sizeof(baddr)) != outlen[1]) | |||
| 581 | err(1, "can't send broadcast packet"); | |||
| 582 | } | |||
| 583 | } | |||
| 584 | ||||
| 585 | /* | |||
| 586 | * We stay in the poll loop for ~5 seconds | |||
| 587 | */ | |||
| 588 | timeout.it_value.tv_sec = 5; | |||
| 589 | timeout.it_value.tv_usec = 0; | |||
| 590 | while (timerisset(&timeout.it_value)((&timeout.it_value)->tv_sec || (&timeout.it_value )->tv_usec)) { | |||
| 591 | pfd[0].fd = sock[0]; | |||
| 592 | pfd[0].events = POLLIN0x0001; | |||
| 593 | pfd[1].fd = sock[1]; | |||
| 594 | pfd[1].events = POLLIN0x0001; | |||
| 595 | setitimer(ITIMER_REAL0, &timeout, NULL((void *)0)); | |||
| 596 | rval = poll(pfd, 2, 0); | |||
| 597 | setitimer(ITIMER_REAL0, NULL((void *)0), &timeout); | |||
| 598 | if (rval == -1) { | |||
| 599 | if (errno(*__errno()) == EINTR4) | |||
| 600 | break; | |||
| 601 | err(1, "poll"); /* shouldn't happen */ | |||
| 602 | } | |||
| 603 | if (pfd[1].revents & POLLIN0x0001) { | |||
| 604 | stat = get_reply(sock[1], (in_port_t)port[1], | |||
| 605 | xid[1], &msg[1], &res[1], rusers_reply_3); | |||
| 606 | if (stat != RPC_SUCCESS) | |||
| 607 | goto cleanup; | |||
| 608 | } | |||
| 609 | if (pfd[0].revents & POLLIN0x0001) { | |||
| 610 | stat = get_reply(sock[0], (in_port_t)port[0], | |||
| ||||
| 611 | xid[0], &msg[0], &res[0], rusers_reply); | |||
| 612 | if (stat != RPC_SUCCESS) | |||
| 613 | goto cleanup; | |||
| 614 | } | |||
| 615 | } | |||
| 616 | } | |||
| 617 | cleanup: | |||
| 618 | if (ifap != NULL((void *)0)) | |||
| 619 | freeifaddrs(ifap); | |||
| 620 | if (sock[0] >= 0) | |||
| 621 | (void)close(sock[0]); | |||
| 622 | if (sock[1] >= 0) | |||
| 623 | (void)close(sock[1]); | |||
| 624 | AUTH_DESTROY(unix_auth)((*((unix_auth)->ah_ops->ah_destroy))(unix_auth)); | |||
| 625 | if (stat != RPC_SUCCESS) { | |||
| 626 | clnt_perrno(stat); | |||
| 627 | exit(1); | |||
| 628 | } | |||
| 629 | } | |||
| 630 | ||||
| 631 | void | |||
| 632 | print_entry(struct host_info *entry, int longfmt) | |||
| 633 | { | |||
| 634 | char date[32], idle_time[64]; | |||
| 635 | char remote[RUSERS_MAXHOSTLEN257 + 3]; | |||
| 636 | struct rusers_utmp *ut; | |||
| 637 | int i, len; | |||
| 638 | ||||
| 639 | if (!longfmt) | |||
| 640 | printf("%-*.*s ", HOST_WIDTH17, HOST_WIDTH17, entry->host); | |||
| 641 | ||||
| 642 | for (i = 0, ut = entry->users; i < entry->count; i++, ut++) { | |||
| 643 | if (longfmt) { | |||
| 644 | time_t tim = ut->ut_time; | |||
| 645 | strftime(date, sizeof(date), "%h %d %R", | |||
| 646 | localtime(&tim)); | |||
| 647 | date[sizeof(date) - 1] = '\0'; | |||
| 648 | fmt_idle(ut->ut_idle, idle_time, sizeof(idle_time)); | |||
| 649 | len = termwidth - | |||
| 650 | (MAXIMUM(strlen(ut->ut_user), NAME_WIDTH)(((strlen(ut->ut_user)) > (8)) ? (strlen(ut->ut_user )) : (8)) + 1 + | |||
| 651 | HOST_WIDTH17 + 1 + LINE_WIDTH8 + 1 + strlen(date) + | |||
| 652 | 1 + MAXIMUM(8, strlen(idle_time))(((8) > (strlen(idle_time))) ? (8) : (strlen(idle_time))) + 1 + 2); | |||
| 653 | if (len > 0 && ut->ut_host[0] != '\0') | |||
| 654 | snprintf(remote, sizeof(remote), "(%.*s)", | |||
| 655 | MINIMUM(len, RUSERS_MAXHOSTLEN)(((len) < (257)) ? (len) : (257)), ut->ut_host); | |||
| 656 | else | |||
| 657 | remote[0] = '\0'; | |||
| 658 | len = HOST_WIDTH17 - MINIMUM(HOST_WIDTH, strlen(entry->host))(((17) < (strlen(entry->host))) ? (17) : (strlen(entry-> host))) + | |||
| 659 | LINE_WIDTH8 - MINIMUM(LINE_WIDTH, strlen(ut->ut_line))(((8) < (strlen(ut->ut_line))) ? (8) : (strlen(ut->ut_line ))); | |||
| 660 | printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n", | |||
| 661 | NAME_WIDTH8, ut->ut_user, HOST_WIDTH17, entry->host, | |||
| 662 | LINE_WIDTH8, ut->ut_line, len, "", date, | |||
| 663 | idle_time, remote); | |||
| 664 | } else { | |||
| 665 | fputs(ut->ut_user, stdout(&__sF[1])); | |||
| 666 | putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', ( &__sF[1]))); | |||
| 667 | } | |||
| 668 | } | |||
| 669 | if (!longfmt) | |||
| 670 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
| 671 | } | |||
| 672 | ||||
| 673 | void | |||
| 674 | expandhosts(void) | |||
| 675 | { | |||
| 676 | struct host_info *new_hostinfo, *entry; | |||
| 677 | u_int count; | |||
| 678 | int i, j; | |||
| 679 | ||||
| 680 | for (i = 0, count = 0; i < nentries; i++) | |||
| 681 | count += hostinfo[i].count; | |||
| 682 | ||||
| 683 | new_hostinfo = calloc(sizeof(*entry), count); | |||
| 684 | if (new_hostinfo == NULL((void *)0)) | |||
| 685 | err(1, NULL((void *)0)); | |||
| 686 | for (i = 0, entry = new_hostinfo; i < nentries; i++) { | |||
| 687 | for (j = 0; j < hostinfo[i].count; j++) { | |||
| 688 | memcpy(entry, &hostinfo[i], sizeof(*entry)); | |||
| 689 | entry->users = &hostinfo[i].users[j]; | |||
| 690 | entry->idle = entry->users->ut_idle; | |||
| 691 | entry->count = 1; | |||
| 692 | entry++; | |||
| 693 | } | |||
| 694 | } | |||
| 695 | free(hostinfo); | |||
| 696 | hostinfo = new_hostinfo; | |||
| 697 | nentries = maxentries = count; | |||
| 698 | } | |||
| 699 | ||||
| 700 | void | |||
| 701 | sorthosts(void) | |||
| 702 | { | |||
| 703 | int i; | |||
| 704 | int (*compar)(const void *, const void *); | |||
| 705 | ||||
| 706 | if (iflag && lflag) | |||
| 707 | expandhosts(); | |||
| 708 | ||||
| 709 | if (hflag) | |||
| 710 | compar = hcompare; | |||
| 711 | else if (iflag) | |||
| 712 | compar = icompare; | |||
| 713 | else | |||
| 714 | compar = ucompare; | |||
| 715 | qsort(hostinfo, nentries, sizeof(*hostinfo), compar); | |||
| 716 | ||||
| 717 | for (i = 0; i < nentries; i++) | |||
| 718 | print_entry(&hostinfo[i], lflag && hostinfo[i].count); | |||
| 719 | } | |||
| 720 | ||||
| 721 | int | |||
| 722 | hcompare(const void *aa, const void *bb) | |||
| 723 | { | |||
| 724 | const struct host_info *a = (struct host_info *)aa; | |||
| 725 | const struct host_info *b = (struct host_info *)bb; | |||
| 726 | int rval; | |||
| 727 | ||||
| 728 | if ((rval = strcasecmp(a->host, b->host)) != 0) | |||
| 729 | return(rval); | |||
| 730 | ||||
| 731 | if (a->idle < b->idle) | |||
| 732 | return(-1); | |||
| 733 | else if (a->idle > b->idle) | |||
| 734 | return(1); | |||
| 735 | ||||
| 736 | if (a->count > b->count) | |||
| 737 | return(-1); | |||
| 738 | else if (a->count < b->count) | |||
| 739 | return(1); | |||
| 740 | ||||
| 741 | return(0); | |||
| 742 | } | |||
| 743 | ||||
| 744 | int | |||
| 745 | icompare(const void *aa, const void *bb) | |||
| 746 | { | |||
| 747 | const struct host_info *a = (struct host_info *)aa; | |||
| 748 | const struct host_info *b = (struct host_info *)bb; | |||
| 749 | ||||
| 750 | if (a->idle < b->idle) | |||
| 751 | return(-1); | |||
| 752 | else if (a->idle > b->idle) | |||
| 753 | return(1); | |||
| 754 | ||||
| 755 | if (a->count > b->count) | |||
| 756 | return(-1); | |||
| 757 | else if (a->count < b->count) | |||
| 758 | return(1); | |||
| 759 | ||||
| 760 | return(strcasecmp(a->host, b->host)); | |||
| 761 | } | |||
| 762 | ||||
| 763 | int | |||
| 764 | ucompare(const void *aa, const void *bb) | |||
| 765 | { | |||
| 766 | const struct host_info *a = (struct host_info *)aa; | |||
| 767 | const struct host_info *b = (struct host_info *)bb; | |||
| 768 | ||||
| 769 | if (a->count > b->count) | |||
| 770 | return(-1); | |||
| 771 | else if (a->count < b->count) | |||
| 772 | return(1); | |||
| 773 | ||||
| 774 | if (a->idle < b->idle) | |||
| 775 | return(-1); | |||
| 776 | else if (a->idle > b->idle) | |||
| 777 | return(1); | |||
| 778 | ||||
| 779 | return(strcasecmp(a->host, b->host)); | |||
| 780 | } | |||
| 781 | ||||
| 782 | void | |||
| 783 | alarmclock(int signo) | |||
| 784 | { | |||
| 785 | ||||
| 786 | ; /* just interrupt */ | |||
| 787 | } | |||
| 788 | ||||
| 789 | char * | |||
| 790 | estrndup(const char *src, size_t len) | |||
| 791 | { | |||
| 792 | char *dst, *end; | |||
| 793 | ||||
| 794 | if ((end = memchr(src, '\0', len)) != NULL((void *)0)) | |||
| 795 | len = end - src; | |||
| 796 | ||||
| 797 | if ((dst = malloc(len + 1)) == NULL((void *)0)) | |||
| 798 | err(1, NULL((void *)0)); | |||
| 799 | memcpy(dst, src, len); | |||
| 800 | dst[len] = '\0'; | |||
| 801 | ||||
| 802 | return(dst); | |||
| 803 | } | |||
| 804 | ||||
| 805 | void | |||
| 806 | usage(void) | |||
| 807 | { | |||
| 808 | ||||
| 809 | fprintf(stderr(&__sF[2]), "usage: %s [-al] [-h | -i | -u] [hosts ...]\n", | |||
| 810 | __progname); | |||
| 811 | exit(1); | |||
| 812 | } |