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