e83238946b9a1410ba8c0cc620fb32e8307690b0
[openafs.git] / src / sys / rmtsysc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * This module (residing in lib/afs/librmtsys.a) implements the client side of
12  * the rpc version (via rx) of non-standard system calls. Currently only rpc
13  * calls of setpag, and pioctl are supported.
14  */
15 #include <afs/param.h>
16 #include <errno.h>
17 #include <limits.h>
18 #include <sys/types.h>
19 #include <afs/vice.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #else
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #include <sys/file.h>
26 #endif
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <rx/xdr.h>
30 #include "rmtsys.h"
31
32
33 #define NOPAG       0xffffffff /* Also defined in afs/afs.h */
34 static afs_int32 hostAddr = 0;
35 static int   hostAddrLookup = 0;
36 char *afs_server=0, server_name[128];
37 afs_int32 host;
38 static afs_int32 SetClientCreds();
39
40 /* Picks up the name of the remote afs client host where the rmtsys 
41  * daemon resides. Since the clients may be diskless and/or readonly
42  * ones we felt it's better to rely on an shell environment
43  * (AFSSERVER) for the host name first. If that is not set, the
44  * $HOME/.AFSSERVER file is checked, otherwise the "/.AFSSERVER" is
45  * used.
46  */
47 afs_int32 GetAfsServerAddr(syscall)
48 char *syscall;
49 {
50     register struct hostent *th;
51     char *getenv();
52
53     if (hostAddrLookup) {
54         /* Take advantage of caching and assume that the remote host
55          * address won't change during a single program's invocation.
56          */
57         return hostAddr;
58     }
59     hostAddrLookup = 1;
60
61     if (!(afs_server = getenv("AFSSERVER"))) {
62         char *home_dir;
63         FILE *fp;
64         int len;
65         
66         if (!(home_dir = getenv("HOME"))) {
67             /* Our last chance is the "/.AFSSERVER" file */
68             fp = fopen("/.AFSSERVER", "r");
69             if (fp == 0) {
70                 return 0;
71             }
72             fgets(server_name, 128, fp);
73             fclose(fp);
74         } else {
75             char pathname[256];
76
77             sprintf(pathname, "%s/%s", home_dir, ".AFSSERVER");
78             fp = fopen(pathname, "r");
79             if (fp == 0) {
80                 /* Our last chance is the "/.AFSSERVER" file */
81                 fp = fopen("/.AFSSERVER", "r");
82                 if (fp == 0) {
83                     return 0;
84                 }
85             }
86             fgets(server_name, 128, fp);
87             fclose(fp);
88         }
89         len = strlen(server_name);
90         if (len == 0) {
91             return 0;
92         }
93         if (server_name[len-1] == '\n') {
94             server_name[len-1] = 0;
95         }
96         afs_server = server_name;
97     }
98     th = gethostbyname(afs_server);
99     if (!th) {
100         printf("host %s not found; %s call aborted\n", afs_server, syscall);
101         return 0;
102     }
103     bcopy(th->h_addr, &hostAddr, sizeof(hostAddr));
104     return hostAddr;
105 }
106
107
108 /* Does the actual RX connection to the afs server */
109 struct rx_connection *rx_connection(errorcode, syscall)
110 afs_int32 *errorcode;
111 char *syscall;
112 {
113     struct rx_connection *conn;
114     struct rx_securityClass *null_securityObject;
115
116     if (!(host = GetAfsServerAddr(syscall))) {
117         *errorcode = -1;
118         return (struct rx_connection *)0;
119     }   
120     *errorcode = rx_Init(0);
121     if(*errorcode) {
122         printf("Rx initialize failed \n");
123         return (struct rx_connection *)0;
124     }
125     null_securityObject = rxnull_NewClientSecurityObject();
126     conn = rx_NewConnection(host, htons(AFSCONF_RMTSYSPORT), RMTSYS_SERVICEID, null_securityObject, 0);
127     if (!conn) {
128         printf("Unable to make a new connection\n");
129         *errorcode = -1;
130         return (struct rx_connection *)0;
131     }
132     return conn;
133 }
134
135
136 /* WARNING: The calling program (i.e. klog) MUST be suid-root since we need to
137  * do a setgroups(2) call with the new pag.... */
138 #ifdef AFS_DUX40_ENV
139 #pragma weak setpag = afs_setpag
140 int afs_setpag()
141 #else
142 int setpag()
143 #endif
144 {
145     struct rx_connection *conn;
146     clientcred creds;
147     afs_int32 errorcode, errornumber, newpag, ngroups, j, groups[NGROUPS_MAX];
148
149     if (!(conn = rx_connection(&errorcode, "setpag"))) {
150         /* Remote call can't be performed for some reason.
151          * Try the local 'setpag' system call ... */
152         errorcode = lsetpag();
153         return errorcode;
154     }
155     ngroups = SetClientCreds(&creds, groups);
156     errorcode = RMTSYS_SetPag(conn, &creds, &newpag, &errornumber);
157     if (errornumber) {
158         errno = errornumber;
159         errorcode = -1;
160         printf("Warning: Remote setpag to %s has failed (err=%d)...\n",
161                 afs_server, errno);
162     }
163     if (errorcode) {
164         return errorcode;
165     }
166     if (afs_get_pag_from_groups(groups[0], groups[1]) == NOPAG) {
167         /* we will have to shift grouplist to make room for pag */
168         if (ngroups + 2 > NGROUPS_MAX) {
169             /* this is what the real setpag returns */
170            errno = E2BIG;
171            return -1;
172         }
173         for (j = ngroups - 1; j >= 0; j--) {
174             groups[j + 2] = groups[j];
175         }
176         ngroups += 2;
177     }
178     afs_get_groups_from_pag(newpag, &groups[0], &groups[1]);
179     if (setgroups(ngroups, groups) == -1) {
180         return -1;
181     }
182 #ifdef  AFS_HPUX_ENV
183     errorcode = setuid(getuid());
184 #else
185     errorcode = setreuid(-1, getuid());
186 #endif /* AFS_HPUX_ENV */
187     return errorcode;
188 }
189
190
191 /* Remote pioctl(2) client routine */
192 #ifdef AFS_DUX40_ENV
193 #pragma weak pioctl = afs_pioctl
194 int afs_pioctl(path, cmd, data, follow) 
195 #else
196 int pioctl(path, cmd, data, follow) 
197 #endif
198 char *path;
199 afs_int32 cmd, follow;
200 struct ViceIoctl *data;
201 {
202     struct rx_connection *conn;
203     clientcred creds;
204     afs_int32 errorcode, groups[NGROUPS_MAX], errornumber, ins= data->in_size;
205     rmtbulk InData, OutData;
206     char pathname[256], *pathp = pathname, *inbuffer;
207 #if 0/*ndef HAVE_GETCWD*/ /* XXX enable when autoconf happens */
208     extern char *getwd();
209 #define getcwd(x,y) getwd(x)
210 #endif
211     if (!(conn = rx_connection(&errorcode, "pioctl"))) {
212         /* Remote call can't be performed for some reason.
213          * Try the local 'pioctl' system call ... */
214         errorcode = lpioctl(path, cmd, data, follow);
215         return errorcode;
216     }
217     (void) SetClientCreds(&creds, groups);
218 #ifdef  AFS_OSF_ENV
219     if (!ins) ins = 1;
220 #endif    
221     if (!(inbuffer = (char *)malloc(ins)))
222          return (-1);       /* helpless here */
223     if (data->in_size)
224         bcopy(data->in, inbuffer, data->in_size);
225     InData.rmtbulk_len = data->in_size;
226     InData.rmtbulk_val = inbuffer;
227     inparam_conversion(cmd, InData.rmtbulk_val, 0);
228     OutData.rmtbulk_len = data->out_size;
229     OutData.rmtbulk_val = data->out;
230     /* We always need to pass absolute pathnames to the remote pioctl since we
231      * lose the current directory value when doing an rpc call. Below we
232      * prepend the current absolute path directory, if the name is relative */
233     if (path) {
234         if (*path != '/') {
235             /* assuming relative path name */
236             if (getcwd(pathname, 256) == NULL) {
237                 free(inbuffer);
238                 printf("getwd failed; exiting\n");
239                 exit(1);
240             } 
241             strcpy(pathname+strlen(pathname), "/");
242             strcat(pathname, path);
243         } else {
244             strcpy(pathname, path);
245         }
246     } else {
247         /* Special meaning for a "NULL" pathname since xdr_string hates nil
248          * pointers, at least on non-RTS; of course the proper solution would
249          * be to change the interface declartion. */
250         strcpy(pathname, NIL_PATHP);
251     }
252     errorcode = RMTSYS_Pioctl(conn, &creds, pathp, cmd,  follow, &InData,
253                               &OutData, &errornumber);
254     if (errornumber) {
255         errno = errornumber;
256         errorcode = -1;         /* Necessary since errorcode is 0 on
257                                  * standard remote pioctl errors */
258         if (errno != EDOM && errno != EACCES)
259             printf("Warning: Remote pioctl to %s has failed (err=%d)...\n",
260                     afs_server, errno);
261     }
262     if (!errorcode) {
263         /* Do the conversions back to the host order; store the results back
264          * on the same buffer */
265         outparam_conversion(cmd, OutData.rmtbulk_val, 1);
266     }
267     free(inbuffer);
268     return errorcode;
269 }
270
271     
272 int afs_get_pag_from_groups(g0, g1)
273 afs_uint32 g0, g1;
274 {
275         afs_uint32 h, l, result;
276
277         g0 -= 0x3f00;
278         g1 -= 0x3f00;
279         if (g0 < 0xc000 && g1 < 0xc000) {
280                 l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
281                 h = (g0 >> 14);
282                 h = (g1 >> 14) + h + h + h;
283                 result =  ((h << 28) | l);
284                 /* Additional testing */        
285                 if (((result >> 24) & 0xff) == 'A')
286                         return result;
287                 else
288                         return NOPAG;
289         }
290         return NOPAG;
291 }
292
293
294 afs_get_groups_from_pag(pag, g0p, g1p)
295 afs_uint32 pag;
296 afs_uint32 *g0p, *g1p;
297 {
298         unsigned short g0, g1;
299
300         pag &= 0x7fffffff;
301         g0 = 0x3fff & (pag >> 14);
302         g1 = 0x3fff & pag;
303         g0 |= ((pag >> 28) / 3) << 14;
304         g1 |= ((pag >> 28) % 3) << 14;
305         *g0p = g0 + 0x3f00;
306         *g1p = g1 + 0x3f00;
307 }
308
309
310 static afs_int32 SetClientCreds(creds, groups)
311 struct clientcred *creds;
312 afs_int32 *groups;
313 {
314     afs_int32 ngroups;
315
316     creds->uid = getuid();
317     groups[0] = groups[1] = 0;
318     ngroups = getgroups(NGROUPS_MAX, groups);
319     creds->group0 = groups[0];
320     creds->group1 = groups[1];
321     return ngroups;
322 }