1 1.26 mrg /* $NetBSD: rusers.c,v 1.26 2019/02/03 10:48:47 mrg Exp $ */ 2 1.12 tls 3 1.1 brezak /*- 4 1.6 brezak * Copyright (c) 1993 John Brezak 5 1.6 brezak * All rights reserved. 6 1.6 brezak * 7 1.6 brezak * Redistribution and use in source and binary forms, with or without 8 1.6 brezak * modification, are permitted provided that the following conditions 9 1.6 brezak * are met: 10 1.6 brezak * 1. Redistributions of source code must retain the above copyright 11 1.6 brezak * notice, this list of conditions and the following disclaimer. 12 1.6 brezak * 2. Redistributions in binary form must reproduce the above copyright 13 1.6 brezak * notice, this list of conditions and the following disclaimer in the 14 1.6 brezak * documentation and/or other materials provided with the distribution. 15 1.6 brezak * 3. The name of the author may not be used to endorse or promote products 16 1.6 brezak * derived from this software without specific prior written permission. 17 1.6 brezak * 18 1.6 brezak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 1.6 brezak * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 1.6 brezak * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 1.6 brezak * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 1.6 brezak * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 1.6 brezak * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 1.6 brezak * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.6 brezak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 1.6 brezak * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 1.6 brezak * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.6 brezak * POSSIBILITY OF SUCH DAMAGE. 29 1.1 brezak */ 30 1.1 brezak 31 1.13 lukem #include <sys/cdefs.h> 32 1.4 mycroft #ifndef lint 33 1.26 mrg __RCSID("$NetBSD: rusers.c,v 1.26 2019/02/03 10:48:47 mrg Exp $"); 34 1.4 mycroft #endif /* not lint */ 35 1.4 mycroft 36 1.1 brezak #include <sys/types.h> 37 1.1 brezak #include <sys/socket.h> 38 1.15 kleink 39 1.13 lukem #include <rpc/rpc.h> 40 1.13 lukem #include <arpa/inet.h> 41 1.14 perry 42 1.13 lukem #include <err.h> 43 1.1 brezak #include <netdb.h> 44 1.1 brezak #include <stdio.h> 45 1.13 lukem #include <stdlib.h> 46 1.14 perry #include <string.h> 47 1.15 kleink #include <time.h> 48 1.14 perry #include <unistd.h> 49 1.6 brezak #include <utmp.h> 50 1.6 brezak 51 1.6 brezak /* 52 1.6 brezak * For now we only try version 2 of the protocol. The current 53 1.9 deraadt * version is 3 (rusers.h), but only Solaris and NetBSD seem 54 1.6 brezak * to support it currently. 55 1.6 brezak */ 56 1.6 brezak #include <rpcsvc/rnusers.h> /* Old version */ 57 1.1 brezak 58 1.13 lukem 59 1.1 brezak #define MAX_INT 0x7fffffff 60 1.1 brezak 61 1.25 joerg static struct timeval timeout = { 25, 0 }; 62 1.25 joerg static int longopt; 63 1.25 joerg static int allopt; 64 1.25 joerg 65 1.25 joerg static void allhosts(void); 66 1.25 joerg static void onehost(char *); 67 1.25 joerg static void remember_host(struct sockaddr *); 68 1.25 joerg static int rusers_reply(char *, struct netbuf *, struct netconfig *); 69 1.25 joerg static int search_host(struct sockaddr *); 70 1.25 joerg __dead static void usage(void); 71 1.13 lukem 72 1.25 joerg static struct host_list { 73 1.1 brezak struct host_list *next; 74 1.19 fvdl int family; 75 1.19 fvdl union { 76 1.19 fvdl struct in6_addr _addr6; 77 1.19 fvdl struct in_addr _addr4; 78 1.19 fvdl } addr; 79 1.1 brezak } *hosts; 80 1.1 brezak 81 1.19 fvdl #define addr6 addr._addr6 82 1.19 fvdl #define addr4 addr._addr4 83 1.19 fvdl 84 1.25 joerg static int 85 1.19 fvdl search_host(struct sockaddr *sa) 86 1.1 brezak { 87 1.1 brezak struct host_list *hp; 88 1.1 brezak 89 1.1 brezak if (!hosts) 90 1.1 brezak return(0); 91 1.1 brezak 92 1.1 brezak for (hp = hosts; hp != NULL; hp = hp->next) { 93 1.19 fvdl switch (hp->family) { 94 1.19 fvdl case AF_INET6: 95 1.19 fvdl if (!memcmp(&hp->addr6, 96 1.19 fvdl &((struct sockaddr_in6 *)sa)->sin6_addr, 97 1.19 fvdl sizeof (struct in6_addr))) 98 1.19 fvdl return 1; 99 1.19 fvdl break; 100 1.19 fvdl case AF_INET: 101 1.19 fvdl if (!memcmp(&hp->addr4, 102 1.19 fvdl &((struct sockaddr_in *)sa)->sin_addr, 103 1.19 fvdl sizeof (struct in_addr))) 104 1.19 fvdl return 1; 105 1.19 fvdl break; 106 1.19 fvdl default: 107 1.20 cgd break; 108 1.19 fvdl } 109 1.1 brezak } 110 1.1 brezak return(0); 111 1.1 brezak } 112 1.1 brezak 113 1.25 joerg static void 114 1.19 fvdl remember_host(struct sockaddr *sa) 115 1.1 brezak { 116 1.1 brezak struct host_list *hp; 117 1.1 brezak 118 1.19 fvdl if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) { 119 1.19 fvdl err(1, "malloc"); 120 1.19 fvdl /* NOTREACHED */ 121 1.19 fvdl } 122 1.19 fvdl hp->family = sa->sa_family; 123 1.1 brezak hp->next = hosts; 124 1.19 fvdl switch (sa->sa_family) { 125 1.19 fvdl case AF_INET6: 126 1.19 fvdl memcpy(&hp->addr6, &((struct sockaddr_in6 *)sa)->sin6_addr, 127 1.19 fvdl sizeof (struct in6_addr)); 128 1.19 fvdl break; 129 1.19 fvdl case AF_INET: 130 1.19 fvdl memcpy(&hp->addr4, &((struct sockaddr_in *)sa)->sin_addr, 131 1.19 fvdl sizeof (struct in_addr)); 132 1.19 fvdl break; 133 1.19 fvdl default: 134 1.19 fvdl err(1, "unknown address family"); 135 1.19 fvdl /* NOTREACHED */ 136 1.19 fvdl } 137 1.1 brezak hosts = hp; 138 1.1 brezak } 139 1.1 brezak 140 1.25 joerg static int 141 1.19 fvdl rusers_reply(char *replyp, struct netbuf *raddrp, struct netconfig *nconf) 142 1.5 deraadt { 143 1.19 fvdl char host[NI_MAXHOST]; 144 1.13 lukem int x; 145 1.6 brezak struct utmpidlearr *up = (struct utmpidlearr *)replyp; 146 1.19 fvdl struct sockaddr *sa = raddrp->buf; 147 1.5 deraadt 148 1.19 fvdl if (search_host(sa)) 149 1.1 brezak return(0); 150 1.1 brezak 151 1.6 brezak if (!allopt && !up->uia_cnt) 152 1.5 deraadt return(0); 153 1.19 fvdl 154 1.19 fvdl if (getnameinfo(sa, sa->sa_len, host, sizeof host, NULL, 0, 0)) 155 1.19 fvdl return 0; 156 1.19 fvdl 157 1.13 lukem #define HOSTWID (int)sizeof(up->uia_arr[0]->ui_utmp.ut_host) 158 1.13 lukem #define LINEWID (int)sizeof(up->uia_arr[0]->ui_utmp.ut_line) 159 1.13 lukem #define NAMEWID (int)sizeof(up->uia_arr[0]->ui_utmp.ut_name) 160 1.13 lukem 161 1.5 deraadt if (!longopt) 162 1.13 lukem printf("%-*.*s ", HOSTWID, HOSTWID, host); 163 1.5 deraadt 164 1.6 brezak for (x = 0; x < up->uia_cnt; x++) { 165 1.13 lukem unsigned int minutes; 166 1.26 mrg char date[26], idle[11]; 167 1.13 lukem char remote[HOSTWID + 3]; /* "(" host ")" \0 */ 168 1.13 lukem char local[HOSTWID + LINEWID + 2]; /* host ":" line \0 */ 169 1.23 mrg time_t uttime; 170 1.13 lukem 171 1.13 lukem if (!longopt) { 172 1.13 lukem printf("%.*s ", NAMEWID, 173 1.13 lukem up->uia_arr[x]->ui_utmp.ut_name); 174 1.13 lukem continue; 175 1.13 lukem } 176 1.13 lukem 177 1.13 lukem snprintf(local, sizeof(local), "%.*s:%s", 178 1.13 lukem HOSTWID, host, 179 1.13 lukem up->uia_arr[x]->ui_utmp.ut_line); 180 1.13 lukem 181 1.23 mrg uttime = up->uia_arr[x]->ui_utmp.ut_time; 182 1.13 lukem snprintf(date, sizeof(date), "%s", 183 1.23 mrg &(ctime(&uttime))[4]); 184 1.13 lukem 185 1.13 lukem minutes = up->uia_arr[x]->ui_idle; 186 1.13 lukem if (minutes == MAX_INT) 187 1.13 lukem strcpy(idle, "??"); 188 1.13 lukem else if (minutes == 0) 189 1.13 lukem strcpy(idle, ""); 190 1.5 deraadt else { 191 1.13 lukem unsigned int days, hours; 192 1.13 lukem 193 1.13 lukem days = minutes / (24 * 60); 194 1.13 lukem minutes %= (24 * 60); 195 1.16 hubertf hours = minutes / 60; 196 1.16 hubertf minutes %= 60; 197 1.13 lukem 198 1.13 lukem if (days > 0) 199 1.13 lukem snprintf(idle, sizeof(idle), "%d d ", days); 200 1.13 lukem else if (hours > 0) 201 1.13 lukem snprintf(idle, sizeof(idle), "%2d:%02d", 202 1.13 lukem hours, minutes); 203 1.13 lukem else 204 1.13 lukem snprintf(idle, sizeof(idle), ":%02d", minutes); 205 1.5 deraadt } 206 1.5 deraadt 207 1.13 lukem if (up->uia_arr[x]->ui_utmp.ut_host[0] != '\0') 208 1.13 lukem snprintf(remote, sizeof(remote), "(%.*s)", 209 1.13 lukem HOSTWID, up->uia_arr[x]->ui_utmp.ut_host); 210 1.13 lukem else 211 1.13 lukem remote[0] = '\0'; 212 1.13 lukem 213 1.13 lukem printf("%-*.*s %-*.*s %-12.12s %8.8s %s\n", 214 1.13 lukem NAMEWID, NAMEWID, up->uia_arr[x]->ui_utmp.ut_name, 215 1.13 lukem HOSTWID+LINEWID+1, HOSTWID+LINEWID+1, local, 216 1.13 lukem date, idle, remote); 217 1.5 deraadt } 218 1.5 deraadt if (!longopt) 219 1.5 deraadt putchar('\n'); 220 1.5 deraadt 221 1.19 fvdl remember_host(sa); 222 1.1 brezak return(0); 223 1.1 brezak } 224 1.1 brezak 225 1.25 joerg static void 226 1.6 brezak onehost(char *host) 227 1.1 brezak { 228 1.6 brezak struct utmpidlearr up; 229 1.5 deraadt CLIENT *rusers_clnt; 230 1.13 lukem enum clnt_stat clnt_stat; 231 1.19 fvdl struct netbuf nb; 232 1.19 fvdl struct addrinfo *ai; 233 1.19 fvdl int ecode; 234 1.5 deraadt 235 1.5 deraadt rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); 236 1.5 deraadt if (rusers_clnt == NULL) { 237 1.21 cgd clnt_pcreateerror(getprogname()); 238 1.5 deraadt exit(1); 239 1.5 deraadt } 240 1.1 brezak 241 1.19 fvdl ecode = getaddrinfo(host, NULL, NULL, &ai); 242 1.19 fvdl if (ecode != 0) 243 1.19 fvdl err(1, "%s", gai_strerror(ecode)); 244 1.19 fvdl 245 1.13 lukem memset((char *)&up, 0, sizeof(up)); 246 1.13 lukem clnt_stat = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, 247 1.13 lukem xdr_utmpidlearr, &up, timeout); 248 1.13 lukem if (clnt_stat != RPC_SUCCESS) 249 1.13 lukem errx(1, "%s", clnt_sperrno(clnt_stat)); 250 1.19 fvdl nb.buf = ai->ai_addr; 251 1.19 fvdl nb.len = nb.maxlen = ai->ai_addrlen; 252 1.19 fvdl rusers_reply((char *)&up, &nb, NULL); 253 1.19 fvdl freeaddrinfo(ai); 254 1.1 brezak } 255 1.1 brezak 256 1.25 joerg static void 257 1.6 brezak allhosts(void) 258 1.1 brezak { 259 1.6 brezak struct utmpidlearr up; 260 1.1 brezak enum clnt_stat clnt_stat; 261 1.1 brezak 262 1.13 lukem memset((char *)&up, 0, sizeof(up)); 263 1.19 fvdl clnt_stat = rpc_broadcast(RUSERSPROG, RUSERSVERS_IDLE, 264 1.24 plunky RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, 265 1.24 plunky (xdrproc_t)xdr_utmpidlearr, (char *)&up, 266 1.24 plunky (resultproc_t)rusers_reply, "udp"); 267 1.13 lukem if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) 268 1.13 lukem errx(1, "%s", clnt_sperrno(clnt_stat)); 269 1.1 brezak } 270 1.1 brezak 271 1.25 joerg static void 272 1.11 jtc usage(void) 273 1.1 brezak { 274 1.22 jmmv fprintf(stderr, "usage: %s [-la] [hosts ...]\n", getprogname()); 275 1.5 deraadt exit(1); 276 1.1 brezak } 277 1.1 brezak 278 1.11 jtc int 279 1.11 jtc main(int argc, char *argv[]) 280 1.1 brezak { 281 1.5 deraadt int ch; 282 1.5 deraadt 283 1.5 deraadt while ((ch = getopt(argc, argv, "al")) != -1) 284 1.5 deraadt switch (ch) { 285 1.5 deraadt case 'a': 286 1.5 deraadt allopt++; 287 1.5 deraadt break; 288 1.5 deraadt case 'l': 289 1.5 deraadt longopt++; 290 1.5 deraadt break; 291 1.5 deraadt default: 292 1.5 deraadt usage(); 293 1.5 deraadt /*NOTREACHED*/ 294 1.5 deraadt } 295 1.3 brezak 296 1.5 deraadt setlinebuf(stdout); 297 1.1 brezak if (argc == optind) 298 1.1 brezak allhosts(); 299 1.1 brezak else { 300 1.1 brezak for (; optind < argc; optind++) 301 1.1 brezak (void) onehost(argv[optind]); 302 1.1 brezak } 303 1.5 deraadt exit(0); 304 1.1 brezak } 305