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