death to register
[openafs.git] / src / kauth / knfs.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  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17
18 #include <stdio.h>
19 #include <afs/stds.h>
20 #include <sys/types.h>
21 #include <ctype.h>
22 #include <sys/stat.h>
23 #include <signal.h>
24 #include <time.h>
25 #include <netdb.h>
26 #include <errno.h>
27 #include <sys/ioctl.h>
28 #include <string.h>
29 #include <afs/vice.h>
30 #include <afs/cmd.h>
31 #include <afs/auth.h>
32 #include <afs/afsutil.h>
33 #include <afs/sys_prototypes.h>
34
35 /*
36 Modifications:
37
38 29 Oct 1992 Patch GetTokens to print something reasonable when there are no tokens.
39
40 */
41
42 /* this is a structure used to communicate with the afs cache mgr, but is
43  * otherwise irrelevant, or worse.
44  */
45 struct ClearToken {
46     afs_int32 AuthHandle;
47     char HandShakeKey[8];
48     afs_int32 ViceId;
49     afs_int32 BeginTimestamp;
50     afs_int32 EndTimestamp;
51 };
52
53
54 static int
55 SetSysname(afs_int32 ahost, afs_int32 auid, char *sysname)
56 {
57     afs_int32 code;
58     afs_int32 pheader[6];
59     char space[1200], *tp;
60     struct ViceIoctl blob;
61     afs_int32 setp = 1;
62
63     /* otherwise we've got the token, now prepare to build the pioctl args */
64     pheader[0] = ahost;
65     pheader[1] = auid;
66     pheader[2] = 0;             /* group low */
67     pheader[3] = 0;             /* group high */
68     pheader[4] = 38 /*VIOC_AFS_SYSNAME */ ;     /* sysname pioctl index */
69     pheader[5] = 1;             /* NFS protocol exporter # */
70
71     /* copy stuff in */
72     memcpy(space, pheader, sizeof(pheader));
73     tp = space + sizeof(pheader);
74
75     /* finally setup the pioctl call's parameters */
76     blob.in_size = sizeof(pheader);
77     blob.in = space;
78     blob.out_size = 0;
79     blob.out = NULL;
80     memcpy(tp, &setp, sizeof(afs_int32));
81     tp += sizeof(afs_int32);
82     strcpy(tp, sysname);
83     blob.in_size += sizeof(afs_int32) + strlen(sysname) + 1;
84     tp += strlen(sysname);
85     *(tp++) = '\0';
86     code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
87     if (code) {
88         code = errno;
89     }
90     return code;
91 }
92
93
94 static int
95 GetTokens(afs_int32 ahost, afs_int32 auid)
96 {
97     struct ViceIoctl iob;
98     afs_int32 pheader[6];
99     char tbuffer[1024];
100     afs_int32 code = 0;
101     int index, newIndex;
102     char *stp;                  /* secret token ptr */
103     struct ClearToken ct;
104     char *tp;
105     afs_int32 temp, gotit = 0;
106     int maxLen;                 /* biggest ticket we can copy */
107     int tktLen;                 /* server ticket length */
108     time_t tokenExpireTime;
109     char UserName[16];
110     struct ktc_token token;
111     struct ktc_principal clientName;
112     time_t current_time;
113     char *expireString;
114
115     current_time = time(0);
116
117     /* otherwise we've got the token, now prepare to build the pioctl args */
118     pheader[0] = ahost;
119     pheader[1] = auid;
120     pheader[2] = 0;             /* group low */
121     pheader[3] = 0;             /* group high */
122     pheader[4] = 8;             /* gettoken pioctl index */
123     pheader[5] = 1;             /* NFS protocol exporter # */
124
125     for (index = 0; index < 200; index++) {     /* sanity check in case pioctl fails */
126         code = ktc_ListTokens(index, &newIndex, &clientName);
127         if (code) {
128             if (code == KTC_NOENT) {
129                 /* all done */
130                 if (!gotit)
131                     printf("knfs: there are no tokens here.\n");
132                 code = 0;
133             }
134             break;              /* done, but failed */
135         }
136         if (strcmp(clientName.name, "afs") != 0)
137             continue;           /* wrong ticket service */
138
139         /* copy stuff in */
140         memcpy(tbuffer, pheader, sizeof(pheader));
141         tp = tbuffer + sizeof(pheader);
142         memcpy(tp, &index, sizeof(afs_int32));
143         tp += sizeof(afs_int32);
144         iob.in = tbuffer;
145         iob.in_size = sizeof(afs_int32) + sizeof(pheader);
146         iob.out = tbuffer;
147         iob.out_size = sizeof(tbuffer);
148         code = pioctl(NULL, _VICEIOCTL(99), &iob, 0);
149         if (code < 0 && errno == EDOM)
150             return KTC_NOENT;
151         else if (code == 0) {
152             /* check to see if this is the right cell/realm */
153             tp = tbuffer;
154             memcpy(&temp, tp, sizeof(afs_int32));       /* get size of secret token */
155             tktLen = temp;      /* remember size of ticket */
156             tp += sizeof(afs_int32);
157             stp = tp;           /* remember where ticket is, for later */
158             tp += temp;         /* skip ticket for now */
159             memcpy(&temp, tp, sizeof(afs_int32));       /* get size of clear token */
160             if (temp != sizeof(struct ClearToken))
161                 return KTC_ERROR;
162             tp += sizeof(afs_int32);    /* skip length */
163             memcpy(&ct, tp, temp);      /* copy token for later use */
164             tp += temp;         /* skip clear token itself */
165             tp += sizeof(afs_int32);    /* skip primary flag */
166             /* tp now points to the cell name */
167             if (strcmp(tp, clientName.cell) == 0) {
168                 /* closing in now, we've got the right cell */
169                 gotit = 1;
170                 maxLen =
171                     sizeof(token) - sizeof(struct ktc_token) +
172                     MAXKTCTICKETLEN;
173                 if (maxLen < tktLen)
174                     return KTC_TOOBIG;
175                 memcpy(token.ticket, stp, tktLen);
176                 token.startTime = ct.BeginTimestamp;
177                 token.endTime = ct.EndTimestamp;
178                 if (ct.AuthHandle == -1)
179                     ct.AuthHandle = 999;
180                 token.kvno = ct.AuthHandle;
181                 memcpy(&token.sessionKey, ct.HandShakeKey,
182                        sizeof(struct ktc_encryptionKey));
183                 token.ticketLen = tktLen;
184                 if ((token.kvno == 999) ||      /* old style bcrypt ticket */
185                     (ct.BeginTimestamp &&       /* new w/ prserver lookup */
186                      (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
187                     sprintf(clientName.name, "AFS ID %d", ct.ViceId);
188                     clientName.instance[0] = 0;
189                 } else {
190                     sprintf(clientName.name, "Unix UID %d", ct.ViceId);
191                     clientName.instance[0] = 0;
192                 }
193                 strcpy(clientName.cell, tp);
194
195                 tokenExpireTime = token.endTime;
196                 strcpy(UserName, clientName.name);
197                 if (clientName.instance[0] != 0) {
198                     strcat(UserName, ".");
199                     strcat(UserName, clientName.instance);
200                 }
201                 if (UserName[0] == 0)
202                     printf("Tokens");
203                 else if (strncmp(UserName, "AFS ID", 6) == 0) {
204                     printf("User's (%s) tokens", UserName);
205                 } else if (strncmp(UserName, "Unix UID", 8) == 0) {
206                     printf("Tokens");
207                 } else
208                     printf("User %s's tokens", UserName);
209                 printf(" for %s%s%s@%s ", clientName.name,
210                        clientName.instance[0] ? "." : "", clientName.instance,
211                        clientName.cell);
212                 if (tokenExpireTime <= current_time)
213                     printf("[>> Expired <<]\n");
214                 else {
215                     expireString = ctime(&tokenExpireTime);
216                     expireString += 4;  /*Move past the day of week */
217                     expireString[12] = '\0';
218                     printf("[Expires %s]\n", expireString);
219                 }
220
221             }
222         }
223     }
224     return code;
225 }
226
227
228 static int
229 NFSUnlog(afs_int32 ahost, afs_int32 auid)
230 {
231     afs_int32 code;
232     afs_int32 pheader[6];
233     char space[1200];
234     struct ViceIoctl blob;
235
236     /* otherwise we've got the token, now prepare to build the pioctl args */
237     pheader[0] = ahost;
238     pheader[1] = auid;
239     pheader[2] = 0;             /* group low */
240     pheader[3] = 0;             /* group high */
241     pheader[4] = 9;             /* unlog pioctl index */
242     pheader[5] = 1;             /* NFS protocol exporter # */
243
244     /* copy stuff in */
245     memcpy(space, pheader, sizeof(pheader));
246
247     /* finally setup the pioctl call's parameters */
248     blob.in_size = sizeof(pheader);
249     blob.in = space;
250     blob.out_size = 0;
251     blob.out = NULL;
252     code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
253     if (code) {
254         code = errno;
255     }
256     return code;
257 }
258
259 /* Copy the AFS service token into the kernel for a particular host and user */
260 static int
261 NFSCopyToken(afs_int32 ahost, afs_int32 auid)
262 {
263     struct ktc_principal client, server;
264     struct ktc_token theTicket;
265     afs_int32 code;
266     afs_int32 pheader[6];
267     char space[1200];
268     struct ClearToken ct;
269     afs_int32 index, newIndex;
270     afs_int32 temp;             /* for bcopy */
271     char *tp;
272     struct ViceIoctl blob;
273
274     for (index = 0;; index = newIndex) {
275         code = ktc_ListTokens(index, &newIndex, &server);
276         if (code) {
277             if (code == KTC_NOENT) {
278                 /* all done */
279                 code = 0;
280             }
281             break;              /* done, but failed */
282         }
283         if (strcmp(server.name, "afs") != 0)
284             continue;           /* wrong ticket service */
285         code = ktc_GetToken(&server, &theTicket, sizeof(theTicket), &client);
286         if (code)
287             return code;
288
289         /* otherwise we've got the token, now prepare to build the pioctl args */
290         pheader[0] = ahost;
291         pheader[1] = auid;
292         pheader[2] = 0;         /* group low */
293         pheader[3] = 0;         /* group high */
294         pheader[4] = 3;         /* set token pioctl index */
295         pheader[5] = 1;         /* NFS protocol exporter # */
296
297         /* copy in the header */
298         memcpy(space, pheader, sizeof(pheader));
299         tp = space + sizeof(pheader);
300         /* copy in the size of the encrypted part */
301         memcpy(tp, &theTicket.ticketLen, sizeof(afs_int32));
302         tp += sizeof(afs_int32);
303         /* copy in the ticket itself */
304         memcpy(tp, theTicket.ticket, theTicket.ticketLen);
305         tp += theTicket.ticketLen;
306         /* copy in "clear token"'s size */
307         temp = sizeof(struct ClearToken);
308         memcpy(tp, &temp, sizeof(afs_int32));
309         tp += sizeof(afs_int32);
310         /* create the clear token and copy *it* in */
311         ct.AuthHandle = theTicket.kvno; /* where we hide the key version # */
312         memcpy(ct.HandShakeKey, &theTicket.sessionKey,
313                sizeof(ct.HandShakeKey));
314
315         ct.ViceId = auid;
316         ct.BeginTimestamp = theTicket.startTime;
317         ct.EndTimestamp = theTicket.endTime;
318         memcpy(tp, &ct, sizeof(ct));
319         tp += sizeof(ct);
320         /* copy in obsolete primary flag */
321         temp = 0;
322         memcpy(tp, &temp, sizeof(afs_int32));
323         tp += sizeof(afs_int32);
324         /* copy in cell name, null terminated */
325         strcpy(tp, server.cell);
326         tp += strlen(server.cell) + 1;
327
328         /* finally setup the pioctl call's parameters */
329         blob.in_size = tp - space;
330         blob.in = space;
331         blob.out_size = 0;
332         blob.out = NULL;
333         code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
334         if (code) {
335             code = errno;
336             break;
337         }
338     }
339     return code;
340 }
341
342 static int
343 cmdproc(struct cmd_syndesc *as, void *arock)
344 {
345     struct hostent *the;
346     char *tp, *sysname = 0;
347     afs_int32 uid, addr;
348     afs_int32 code;
349
350     the = (struct hostent *)
351         hostutil_GetHostByName(tp = as->parms[0].items->data);
352     if (!the) {
353         printf("knfs: unknown host '%s'.\n", tp);
354         return -1;
355     }
356     memcpy(&addr, the->h_addr, sizeof(afs_int32));
357     uid = -1;
358     if (as->parms[1].items) {
359         code = util_GetInt32(tp = as->parms[1].items->data, &uid);
360         if (code) {
361             printf("knfs: can't parse '%s' as a number (UID)\n", tp);
362             return code;
363         }
364     } else
365         uid = -1;               /* means wildcard: match any user on this host */
366
367     /*
368      * If not "-id" is passed then we use the getuid() id, unless it's root
369      * that is doing it in which case we only authenticate as "system:anyuser"
370      * as it's appropriate for root. (The cm handles conversions from 0 to
371      * "afs_nobody"!)
372      */
373     if (uid == -1) {
374         uid = getuid();
375     }
376
377     if (as->parms[2].items) {
378         sysname = as->parms[2].items->data;
379     }
380
381     if (as->parms[4].items) {
382         /* tokens specified */
383         code = GetTokens(addr, uid);
384         if (code) {
385             if (code == ENOEXEC)
386                 printf
387                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
388             else
389                 printf("knfs: failed to get tokens for uid %d (code %d)\n",
390                        uid, code);
391         }
392         return code;
393     }
394
395     /* finally, parsing is done, make the call */
396     if (as->parms[3].items) {
397         /* unlog specified */
398         code = NFSUnlog(addr, uid);
399         if (code) {
400             if (code == ENOEXEC)
401                 printf
402                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
403             else
404                 printf("knfs: failed to unlog (code %d)\n", code);
405         }
406     } else {
407         code = NFSCopyToken(addr, uid);
408         if (code) {
409             if (code == ENOEXEC)
410                 printf
411                     ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
412             else
413                 printf("knfs: failed to copy tokens (code %d)\n", code);
414         }
415         if (sysname) {
416             code = SetSysname(addr, uid, sysname);
417             if (code) {
418                 printf("knfs: failed to set client's @sys to %s (code %d)\n",
419                        sysname, code);
420             }
421         }
422     }
423     return code;
424 }
425
426 #include "AFS_component_version_number.c"
427
428 int
429 main(int argc, char **argv)
430 {
431     struct cmd_syndesc *ts;
432     afs_int32 code;
433
434 #ifdef  AFS_AIX32_ENV
435     /*
436      * The following signal action for AIX is necessary so that in case of a 
437      * crash (i.e. core is generated) we can include the user's data section 
438      * in the core dump. Unfortunately, by default, only a partial core is
439      * generated which, in many cases, isn't too useful.
440      */
441     struct sigaction nsa;
442
443     sigemptyset(&nsa.sa_mask);
444     nsa.sa_handler = SIG_DFL;
445     nsa.sa_flags = SA_FULLDUMP;
446     sigaction(SIGABRT, &nsa, NULL);
447     sigaction(SIGSEGV, &nsa, NULL);
448 #endif
449
450     ts = cmd_CreateSyntax(NULL, cmdproc, NULL, "copy tickets for NFS");
451     cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_REQUIRED, "host name");
452     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "user ID (decimal)");
453     cmd_AddParm(ts, "-sysname", CMD_SINGLE, CMD_OPTIONAL,
454                 "host's '@sys' value");
455     cmd_AddParm(ts, "-unlog", CMD_FLAG, CMD_OPTIONAL, "unlog remote user");
456     cmd_AddParm(ts, "-tokens", CMD_FLAG, CMD_OPTIONAL,
457                 "display all tokens for remote [host,id]");
458
459     code = cmd_Dispatch(argc, argv);
460     return code;
461 }