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