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