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