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