LINUX: Return NULL for afs_linux_raw_open error
[openafs.git] / src / afs / afs_pag_call.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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"
17 #include "rx/rx_globals.h"
18 #include "rx/rxstat.h"
19 #if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV)
20 #include "net/if.h"
21 #include "netinet/in_var.h"
22 #endif /* !defined(UKERNEL) */
23 #include "rmtsys.h"
24 #include "pagcb.h"
25
26
27 afs_int32 afs_termState = 0;
28 afs_int32 afs_gcpags = AFS_GCPAGS;
29 enum afs_shutdown_state afs_shuttingdown = AFS_RUNNING;
30 int afs_cold_shutdown = 0;
31 int afs_resourceinit_flag = 0;
32 afs_int32 afs_nfs_server_addr;
33 struct interfaceAddr afs_cb_interface;
34 struct afs_osi_WaitHandle AFS_WaitHandler;
35 static struct rx_securityClass *srv_secobj;
36 static struct rx_securityClass *clt_secobj;
37 static struct rx_service *stats_svc;
38 static struct rx_service *pagcb_svc;
39 static struct rx_connection *rmtsys_conn;
40 char *afs_sysname = 0;
41 char *afs_sysnamelist[MAXNUMSYSNAMES];
42 int afs_sysnamecount = 0;
43 int afs_sysnamegen = 0;
44 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
45
46
47 void
48 afs_Daemon(void)
49 {
50     afs_int32 now, last10MinCheck, last60MinCheck;
51
52     last10MinCheck = 0;
53     last60MinCheck = 0;
54     while (1) {
55         rx_CheckPackets();
56         now = osi_Time();
57
58         if (last10MinCheck + 600 < now) {
59             afs_GCUserData();
60         }
61
62         if (last60MinCheck + 3600 < now) {
63             afs_int32 didany;
64             afs_GCPAGs(&didany);
65         }
66
67         now = 20000 - (osi_Time() - now);
68         afs_osi_Wait(now, &AFS_WaitHandler, 0);
69
70         if (afs_termState == AFSOP_STOP_AFS) {
71 #if defined(RXK_LISTENER_ENV)
72             afs_termState = AFSOP_STOP_RXEVENT;
73 #else
74             afs_termState = AFSOP_STOP_COMPLETE;
75 #endif
76             afs_osi_Wakeup(&afs_termState);
77             return;
78         }
79     }
80 }
81
82
83 void
84 afspag_Init(afs_int32 nfs_server_addr)
85 {
86     struct clientcred ccred;
87     struct rmtbulk idata, odata;
88     afs_int32 code, err, addr, obuf;
89     int i;
90
91     afs_uuid_create(&afs_cb_interface.uuid);
92
93     AFS_GLOCK();
94
95     afs_InitStats();
96     rx_Init(htons(7001));
97
98     AFS_STATCNT(afs_ResourceInit);
99     AFS_RWLOCK_INIT(&afs_xuser, "afs_xuser");
100     AFS_RWLOCK_INIT(&afs_xpagcell, "afs_xpagcell");
101     AFS_RWLOCK_INIT(&afs_xpagsys, "afs_xpagsys");
102     AFS_RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock");
103
104     afs_resourceinit_flag = 1;
105     afs_nfs_server_addr = nfs_server_addr;
106     for (i = 0; i < MAXNUMSYSNAMES; i++) {
107         afs_sysnamelist[i] = afs_osi_Alloc(MAXSYSNAME);
108         osi_Assert(afs_sysnamelist[i] != NULL);
109     }
110     afs_sysname = afs_sysnamelist[0];
111     strcpy(afs_sysname, SYS_NAME);
112     afs_sysnamecount = 1;
113     afs_sysnamegen++;
114
115     srv_secobj = rxnull_NewServerSecurityObject();
116     stats_svc = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", &srv_secobj,
117                               1, RXSTATS_ExecuteRequest);
118     pagcb_svc = rx_NewService(0, PAGCB_SERVICEID, "pagcb", &srv_secobj,
119                               1, PAGCB_ExecuteRequest);
120     rx_StartServer(0);
121
122     clt_secobj = rxnull_NewClientSecurityObject();
123     rmtsys_conn = rx_NewConnection(nfs_server_addr, htons(7009),
124                                    RMTSYS_SERVICEID, clt_secobj, 0);
125
126 #ifdef RXK_LISTENER_ENV
127     afs_start_thread(rxk_Listener,       "Rx Listener");
128 #endif
129     afs_start_thread((void *)(void *)rx_ServerProc,      "Rx Server Thread");
130     afs_start_thread(afs_rxevent_daemon, "Rx Event Daemon");
131     afs_start_thread(afs_Daemon,         "AFS PAG Daemon");
132
133     afs_icl_InitLogs();
134
135     AFS_GUNLOCK();
136
137     /* If it's reachable, tell the translator to nuke our creds.
138      * We should be more agressive about making sure this gets done,
139      * even if the translator is unreachable when we boot.
140      */
141     addr = obuf = err = 0;
142     idata.rmtbulk_len = sizeof(addr);
143     idata.rmtbulk_val = (char *)&addr;
144     odata.rmtbulk_len = sizeof(obuf);
145     odata.rmtbulk_val = (char *)&obuf;
146     memset(&ccred, 0, sizeof(ccred));
147     code = RMTSYS_Pioctl(rmtsys_conn, &ccred, NIL_PATHP, 0x4F01, 0,
148                          &idata, &odata, &err);
149 }                               /*afs_ResourceInit */
150
151
152 /* called with the GLOCK held */
153 void
154 afspag_Shutdown(void)
155 {
156     if (afs_shuttingdown != AFS_RUNNING)
157         return;
158     afs_shuttingdown = AFS_SHUTDOWN;
159     afs_termState = AFSOP_STOP_RXCALLBACK;
160     rx_WakeupServerProcs();
161     while (afs_termState == AFSOP_STOP_RXCALLBACK)
162         afs_osi_Sleep(&afs_termState);
163     /* rx_ServerProc sets AFS_STOP_AFS */
164
165     while (afs_termState == AFSOP_STOP_AFS) {
166         afs_osi_CancelWait(&AFS_WaitHandler);
167         afs_osi_Sleep(&afs_termState);
168     }
169     /* afs_Daemon sets AFS_STOP_RXEVENT */
170
171 #if defined(RXK_LISTENER_ENV)
172     while (afs_termState == AFSOP_STOP_RXEVENT)
173         afs_osi_Sleep(&afs_termState);
174     /* afs_rxevent_daemon sets AFSOP_STOP_RXK_LISTENER */
175
176     afs_osi_UnmaskRxkSignals();
177     osi_StopListener();
178     while (afs_termState == AFSOP_STOP_RXK_LISTENER)
179         afs_osi_Sleep(&afs_termState);
180     /* rxk_Listener sets AFSOP_STOP_COMPLETE */
181 #endif
182 }
183
184 static void
185 token_conversion(char *buffer, int buf_size, int in)
186 {
187     struct ClearToken *ticket;
188     afs_int32 *lptr, n;
189
190     /* secret ticket */
191     if (buf_size < 4) return;
192     lptr = (afs_int32 *)buffer;
193     buffer += 4; buf_size -= 4;
194     if (in) {
195         *lptr = ntohl(*lptr);
196         n = *lptr;
197     } else {
198         n = *lptr;
199         *lptr = htonl(*lptr);
200     }
201     if (n < 0 || buf_size < n) return;
202     buffer += n; buf_size -= n;
203
204     /* clear token */
205     if (buf_size < 4) return;
206     lptr = (afs_int32 *)buffer;
207     buffer += 4; buf_size -= 4;
208     if (in) {
209         *lptr = ntohl(*lptr);
210         n = *lptr;
211     } else {
212         n = *lptr;
213         *lptr = htonl(*lptr);
214     }
215     if (n < 0 || buf_size < n) return;
216     if (n >= sizeof(struct ClearToken)) {
217         ticket = (struct ClearToken *)buffer;
218         if (in) {
219             ticket->AuthHandle     = ntohl(ticket->AuthHandle);
220             ticket->ViceId         = ntohl(ticket->ViceId);
221             ticket->BeginTimestamp = ntohl(ticket->BeginTimestamp);
222             ticket->EndTimestamp   = ntohl(ticket->EndTimestamp);
223         } else {
224             ticket->AuthHandle     = htonl(ticket->AuthHandle);
225             ticket->ViceId         = htonl(ticket->ViceId);
226             ticket->BeginTimestamp = htonl(ticket->BeginTimestamp);
227             ticket->EndTimestamp   = htonl(ticket->EndTimestamp);
228         }
229     }
230     buffer += n; buf_size -= n;
231
232     /* primary flag */
233     if (buf_size < 4) return;
234     lptr = (afs_int32 *)buffer;
235     if (in) {
236         *lptr = ntohl(*lptr);
237     } else {
238         *lptr = htonl((*lptr) & ~0x8000);
239     }
240     return;
241 }
242
243 static void
244 FetchVolumeStatus_conversion(char *buffer, int buf_size, int in)
245 {
246     AFSFetchVolumeStatus *status = (AFSFetchVolumeStatus *)buffer;
247
248     if (buf_size < sizeof(AFSFetchVolumeStatus))
249         return;
250     if (in) {
251         status->Vid              = ntohl(status->Vid);
252         status->ParentId         = ntohl(status->ParentId);
253         status->Type             = ntohl(status->Type);
254         status->MinQuota         = ntohl(status->MinQuota);
255         status->MaxQuota         = ntohl(status->MaxQuota);
256         status->BlocksInUse      = ntohl(status->BlocksInUse);
257         status->PartBlocksAvail  = ntohl(status->PartBlocksAvail);
258         status->PartMaxBlocks    = ntohl(status->PartMaxBlocks);
259     } else {
260         status->Vid              = htonl(status->Vid);
261         status->ParentId         = htonl(status->ParentId);
262         status->Type             = htonl(status->Type);
263         status->MinQuota         = htonl(status->MinQuota);
264         status->MaxQuota         = htonl(status->MaxQuota);
265         status->BlocksInUse      = htonl(status->BlocksInUse);
266         status->PartBlocksAvail  = htonl(status->PartBlocksAvail);
267         status->PartMaxBlocks    = htonl(status->PartMaxBlocks);
268     }
269 }
270
271 static void
272 inparam_conversion(int cmd, char *buffer, int buf_size, int in)
273 {
274     afs_int32 *lptr = (afs_int32 *)buffer;
275
276     switch (cmd & 0xffff) {
277         case (0x5600 |  3): /* VIOCSETTOK */
278             token_conversion(buffer, buf_size, in);
279             return;
280
281         case (0x5600 |  5): /* VIOCSETVOLSTAT */
282             FetchVolumeStatus_conversion(buffer, buf_size, in);
283             return;
284
285         case (0x5600 |  8): /* VIOCGETTOK */
286         case (0x5600 | 10): /* VIOCCKSERV */
287         case (0x5600 | 20): /* VIOCACCESS */
288         case (0x5600 | 24): /* VIOCSETCACHESIZE */
289         case (0x5600 | 27): /* VIOCGETCELL */
290         case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */
291         case (0x5600 | 34): /* VIOC_VENUSLOG */
292         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
293         case (0x5600 | 39): /* VIOC_EXPORTAFS */
294             /* one 32-bit integer */
295             if (buf_size >= 4) {
296                 if (in) lptr[0] = ntohl(lptr[0]);
297                 else    lptr[0] = htonl(lptr[0]);
298             }
299             return;
300
301         case (0x5600 | 36): /* VIOCSETCELLSTATUS */
302             /* two 32-bit integers */
303             if (buf_size >= 4) {
304                 if (in) lptr[0] = ntohl(lptr[0]);
305                 else    lptr[0] = htonl(lptr[0]);
306             }
307             if (buf_size >= 8) {
308                 if (in) lptr[1] = ntohl(lptr[1]);
309                 else    lptr[1] = htonl(lptr[1]);
310             }
311             return;
312     }
313 }
314
315 static void
316 outparam_conversion(int cmd, char *buffer, int buf_size, int in)
317 {
318     afs_int32 *lptr = (afs_int32 *)buffer;
319     int i;
320
321     switch (cmd & 0xffff) {
322         case (0x5600 |  4): /* VIOCGETVOLSTAT */
323         case (0x5600 |  5): /* VIOCSETVOLSTAT */
324             FetchVolumeStatus_conversion(buffer, buf_size, in);
325             return;
326
327         case (0x5600 |  8): /* VIOCGETTOK */
328             token_conversion(buffer, buf_size, in);
329             return;
330
331         case (0x5600 | 12): /* VIOCCKCONN */
332         case (0x5600 | 32): /* VIOC_AFS_MARINER_HOST */
333         case (0x5600 | 34): /* VIOC_VENUSLOG */
334         case (0x5600 | 35): /* VIOC_GETCELLSTATUS */
335         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
336         case (0x5600 | 39): /* VIOC_EXPORTAFS */
337             /* one 32-bit integer */
338             if (buf_size >= 4) {
339                 if (in) lptr[0] = ntohl(lptr[0]);
340                 else    lptr[0] = htonl(lptr[0]);
341             }
342             return;
343
344         case (0x5600 | 40): /* VIOCGETCACHEPARMS */
345             /* sixteen 32-bit integers */
346             for (i = 0; i < 16 && buf_size >= 4; i++) {
347                 if (in) lptr[i] = ntohl(lptr[i]);
348                 else    lptr[i] = htonl(lptr[i]);
349                 buf_size -= 4;
350             }
351             return;
352     }
353 }
354
355
356 /* called with the GLOCK held */
357 int
358 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
359 {
360     cred_t *credp = crref();    /* don't free until done! */
361     struct afs_ioctl data;
362     struct clientcred ccred;
363     struct rmtbulk idata, odata;
364     short in_size, out_size;
365     afs_int32 code = 0, pag, err;
366     gid_t g0, g1;
367     char *abspath, *pathbuf = 0;
368
369     AFS_STATCNT(afs_syscall_pioctl);
370     if (follow)
371         follow = 1;             /* compat. with old venus */
372     code = copyin_afs_ioctl(cmarg, &data);
373     if (code) goto out;
374
375     if ((com & 0xff) == 90) {
376         /* PSetClientContext, in any space */
377         code = EINVAL;
378         goto out;
379     }
380
381     /* Special handling for a few pioctls */
382     switch (com & 0xffff) {
383         case (0x5600 |  3): /* VIOCSETTOK */
384             code = afspag_PSetTokens(data.in, data.in_size, &credp);
385             if (code) goto out;
386             break;
387
388         case (0x5600 |  9): /* VIOCUNLOG */
389         case (0x5600 | 21): /* VIOCUNPAG */
390             code = afspag_PUnlog(data.in, data.in_size, &credp);
391             if (code) goto out;
392             break;
393
394         case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
395             code = afspag_PSetSysName(data.in, data.in_size, &credp);
396             if (code) goto out;
397             break;
398     }
399
400     /* Set up credentials */
401     memset(&ccred, 0, sizeof(ccred));
402     pag = PagInCred(credp);
403     ccred.uid = afs_cr_uid(credp);
404     if (pag != NOPAG) {
405          afs_get_groups_from_pag(pag, &g0, &g1);
406          ccred.group0 = g0;
407          ccred.group1 = g1;
408     }
409
410     /*
411      * Copy the path and convert to absolute, if one was given.
412      * NB: We can only use osI_AllocLargeSpace here as long as
413      * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ.
414      */
415     if (path) {
416         pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN);
417         if (!pathbuf) {
418             code = ENOMEM;
419             goto out;
420         }
421         code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath);
422         if (code)
423             goto out_path;
424     } else {
425         abspath = NIL_PATHP;
426     }
427
428     /* Allocate, copy, and convert incoming data */
429     idata.rmtbulk_len = in_size = data.in_size;
430     if (in_size  < 0 || in_size  > MAXBUFFERLEN) {
431         code = EINVAL;
432         goto out_path;
433     }
434     if (in_size > AFS_LRALLOCSIZ)
435          idata.rmtbulk_val = osi_Alloc(in_size);
436     else
437          idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
438     if (!idata.rmtbulk_val) {
439         code = ENOMEM;
440         goto out_path;
441     }
442     if (in_size) {
443         AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code);
444         if (code)
445             goto out_idata;
446         inparam_conversion(com, idata.rmtbulk_val, in_size, 0);
447     }
448
449     /* Allocate space for outgoing data */
450     odata.rmtbulk_len = out_size = data.out_size;
451     if (out_size < 0 || out_size > MAXBUFFERLEN) {
452         code = EINVAL;
453         goto out_idata;
454     }
455     if (out_size > AFS_LRALLOCSIZ)
456          odata.rmtbulk_val = osi_Alloc(out_size);
457     else
458          odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
459     if (!odata.rmtbulk_val) {
460         code = ENOMEM;
461         goto out_idata;
462     }
463
464     AFS_GUNLOCK();
465     code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow,
466                          &idata, &odata, &err);
467     AFS_GLOCK();
468     if (code)
469         goto out_odata;
470
471     /* Convert and copy out the result */
472     if (odata.rmtbulk_len > out_size) {
473         code = E2BIG;
474         goto out_odata;
475     }
476     if (odata.rmtbulk_len) {
477         outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1);
478         AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code);
479     }
480     if (!code)
481         code = err;
482
483 out_odata:
484     if (out_size > AFS_LRALLOCSIZ)
485         osi_Free(odata.rmtbulk_val, out_size);
486     else
487         osi_FreeLargeSpace(odata.rmtbulk_val);
488
489 out_idata:
490     if (in_size > AFS_LRALLOCSIZ)
491         osi_Free(idata.rmtbulk_val, in_size);
492     else
493         osi_FreeLargeSpace(idata.rmtbulk_val);
494
495 out_path:
496     if (path)
497         osi_FreeLargeSpace(pathbuf);
498
499 out:
500     crfree(credp);
501 #if defined(KERNEL_HAVE_UERROR)
502     if (!getuerror())
503         setuerror(code);
504     return (getuerror());
505 #else
506     return (code);
507 #endif
508 }
509
510
511 int
512 afs_syscall_call(parm, parm2, parm3, parm4, parm5, parm6)
513      long parm, parm2, parm3, parm4, parm5, parm6;
514 {
515     /* Superusers may shut us down, such as with afsd -shutdown. */
516     if (parm == AFSOP_SHUTDOWN && afs_suser(NULL))
517     {
518         AFS_GLOCK();
519         afspag_Shutdown();
520         AFS_GUNLOCK();
521         return 0;
522     }
523
524     /* otherwise, we don't support afs_syscall_call, period */
525 #if defined(KERNEL_HAVE_UERROR)
526     setuerror(EPERM);
527 #endif
528     return EPERM;
529 }