1 /* $OpenBSD: dumprmt.c,v 1.26 2009/10/27 23:59:32 deraadt Exp $ */ 2 /* $NetBSD: dumprmt.c,v 1.17 1997/06/05 16:10:47 mrg Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/mtio.h> 35 #include <sys/ioctl.h> 36 #include <sys/socket.h> 37 #include <sys/time.h> 38 #include <ufs/ufs/dinode.h> 39 40 #include <netinet/in.h> 41 #include <netinet/tcp.h> 42 43 #include <protocols/dumprestore.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <netdb.h> 48 #include <errno.h> 49 #include <pwd.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "pathnames.h" 57 #include "dump.h" 58 59 #define TS_CLOSED 0 60 #define TS_OPEN 1 61 62 static int rmtstate = TS_CLOSED; 63 static int rmtape; 64 static char *rmtpeer; 65 66 static int okname(char *); 67 static int rmtcall(char *, char *); 68 static void rmtconnaborted(int); 69 static int rmtgetb(void); 70 static void rmtgetconn(void); 71 static void rmtgets(char *, int); 72 static int rmtreply(char *); 73 74 extern int ntrec; /* blocking factor on tape */ 75 76 int 77 rmthost(char *host) 78 { 79 int len = strlen(host) + 1; 80 81 rmtpeer = malloc(len); 82 if (rmtpeer) 83 strlcpy(rmtpeer, host, len); 84 else 85 rmtpeer = host; 86 signal(SIGPIPE, rmtconnaborted); 87 rmtgetconn(); 88 if (rmtape < 0) 89 return (0); 90 return (1); 91 } 92 93 /* ARGSUSED */ 94 static void 95 rmtconnaborted(int signo) 96 { 97 /* XXX signal race */ 98 errx(X_ABORT, "Lost connection to remote host."); 99 } 100 101 void 102 rmtgetconn(void) 103 { 104 char *cp; 105 static struct servent *sp = NULL; 106 static struct passwd *pwd = NULL; 107 static int on = 1; 108 char *tuser, *name; 109 int size; 110 int maxseg; 111 112 if (sp == NULL) { 113 sp = getservbyname("shell", "tcp"); 114 if (sp == NULL) 115 errx(X_STARTUP, "shell/tcp: unknown service"); 116 pwd = getpwuid(getuid()); 117 if (pwd == NULL) 118 errx(X_STARTUP, "who are you?"); 119 } 120 if ((name = strdup(pwd->pw_name)) == NULL) 121 err(X_STARTUP, "malloc"); 122 if ((cp = strchr(rmtpeer, '@')) != NULL) { 123 tuser = rmtpeer; 124 *cp = '\0'; 125 if (!okname(tuser)) 126 exit(X_STARTUP); 127 rmtpeer = ++cp; 128 } else 129 tuser = name; 130 131 rmtape = rcmd(&rmtpeer, sp->s_port, name, tuser, _PATH_RMT, NULL); 132 (void)free(name); 133 if (rmtape < 0) 134 return; 135 136 size = ntrec * TP_BSIZE; 137 if (size > 60 * 1024) /* XXX */ 138 size = 60 * 1024; 139 /* Leave some space for rmt request/response protocol */ 140 size += 2 * 1024; 141 while (size > TP_BSIZE && 142 setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) 143 size -= TP_BSIZE; 144 (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 145 146 maxseg = 1024; 147 (void)setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG, &maxseg, 148 sizeof(maxseg)); 149 150 (void) setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); 151 } 152 153 static int 154 okname(char *cp0) 155 { 156 char *cp; 157 int c; 158 159 for (cp = cp0; *cp; cp++) { 160 c = *cp; 161 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { 162 warnx("invalid user name: %s", cp0); 163 return (0); 164 } 165 } 166 return (1); 167 } 168 169 int 170 rmtopen(char *tape, int mode) 171 { 172 char buf[256]; 173 174 (void)snprintf(buf, sizeof(buf), "O%s\n%d\n", tape, mode); 175 rmtstate = TS_OPEN; 176 return (rmtcall(tape, buf)); 177 } 178 179 void 180 rmtclose(void) 181 { 182 183 if (rmtstate != TS_OPEN) 184 return; 185 rmtcall("close", "C\n"); 186 rmtstate = TS_CLOSED; 187 } 188 189 int 190 rmtread(char *buf, int count) 191 { 192 char line[30]; 193 int n, i, cc; 194 195 (void)snprintf(line, sizeof(line), "R%d\n", count); 196 n = rmtcall("read", line); 197 if (n < 0) { 198 errno = n; 199 return (-1); 200 } 201 for (i = 0; i < n; i += cc) { 202 cc = read(rmtape, buf+i, n - i); 203 if (cc <= 0) { 204 rmtconnaborted(0); 205 } 206 } 207 return (n); 208 } 209 210 int 211 rmtwrite(char *buf, int count) 212 { 213 char line[30]; 214 215 (void)snprintf(line, sizeof(line), "W%d\n", count); 216 write(rmtape, line, strlen(line)); 217 write(rmtape, buf, count); 218 return (rmtreply("write")); 219 } 220 221 int 222 rmtseek(int offset, int pos) 223 { 224 char line[80]; 225 226 (void)snprintf(line, sizeof(line), "L%d\n%d\n", offset, pos); 227 return (rmtcall("seek", line)); 228 } 229 230 int 231 rmtioctl(int cmd, int count) 232 { 233 char buf[256]; 234 235 if (count < 0) 236 return (-1); 237 (void)snprintf(buf, sizeof(buf), "I%d\n%d\n", cmd, count); 238 return (rmtcall("ioctl", buf)); 239 } 240 241 static int 242 rmtcall(char *cmd, char *buf) 243 { 244 245 if (write(rmtape, buf, strlen(buf)) != strlen(buf)) 246 rmtconnaborted(0); 247 return (rmtreply(cmd)); 248 } 249 250 static int 251 rmtreply(char *cmd) 252 { 253 char *cp; 254 char code[30], emsg[BUFSIZ]; 255 256 rmtgets(code, sizeof(code)); 257 if (*code == 'E' || *code == 'F') { 258 rmtgets(emsg, sizeof(emsg)); 259 msg("%s: %s", cmd, emsg); 260 errno = atoi(&code[1]); 261 if (*code == 'F') 262 rmtstate = TS_CLOSED; 263 return (-1); 264 } 265 if (*code != 'A') { 266 /* Kill trailing newline */ 267 cp = code + strlen(code); 268 if (cp > code && *--cp == '\n') 269 *cp = '\0'; 270 271 msg("Protocol to remote tape server botched (code \"%s\").\n", 272 code); 273 rmtconnaborted(0); 274 } 275 return (atoi(code + 1)); 276 } 277 278 int 279 rmtgetb(void) 280 { 281 char c; 282 283 if (read(rmtape, &c, 1) != 1) 284 rmtconnaborted(0); 285 return (c); 286 } 287 288 /* Get a line (guaranteed to have a trailing newline). */ 289 void 290 rmtgets(char *line, int len) 291 { 292 char *cp = line; 293 294 while (len > 1) { 295 *cp = rmtgetb(); 296 if (*cp == '\n') { 297 cp[1] = '\0'; 298 return; 299 } 300 cp++; 301 len--; 302 } 303 *cp = '\0'; 304 msg("Protocol to remote tape server botched.\n"); 305 msg("(rmtgets got \"%s\").\n", line); 306 rmtconnaborted(0); 307 } 308