Add interface to select client security objects
[openafs.git] / src / ptserver / ptuser.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 #if defined(UKERNEL)
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17
18 #if defined(UKERNEL)
19 #include "afs/sysincludes.h"
20 #include "afs_usrops.h"
21 #include "afsincludes.h"
22 #include "afs/stds.h"
23 #include "rx/rx.h"
24 #include "rx/xdr.h"
25 #include "afs/auth.h"
26 #include "afs/cellconfig.h"
27 #include "afs/afsutil.h"
28 #include "afs/ptclient.h"
29 #include "afs/ptuser.h"
30 #include "afs/pterror.h"
31 #include "afs/com_err.h"
32 #else /* defined(UKERNEL) */
33 #include <afs/stds.h>
34 #include <ctype.h>
35 #include <sys/types.h>
36 #ifdef AFS_NT40_ENV
37 #include <winsock2.h>
38 #else
39 #include <netinet/in.h>
40 #endif
41 #include <stdio.h>
42 #include <string.h>
43 #include <rx/rx.h>
44 #include <rx/xdr.h>
45 #include <afs/auth.h>
46 #include <afs/cellconfig.h>
47 #include <afs/afsutil.h>
48 #include <afs/com_err.h>
49 #include "ptclient.h"
50 #include "ptuser.h"
51 #include "pterror.h"
52 #endif /* defined(UKERNEL) */
53
54
55 struct ubik_client *pruclient = 0;
56 static afs_int32 lastLevel;     /* security level pruclient, if any */
57
58 static char *whoami = "libprot";
59
60 afs_int32
61 pr_Initialize(IN afs_int32 secLevel, IN const char *confDir, IN char *cell)
62 {
63     afs_int32 code;
64     struct rx_connection *serverconns[MAXSERVERS];
65     struct rx_securityClass *sc;
66     static struct afsconf_dir *tdir = (struct afsconf_dir *)NULL;       /* only do this once */
67     static char tconfDir[100] = "";
68     static char tcell[64] = "";
69     afs_int32 scIndex;
70     afs_int32 secFlags;
71     static struct afsconf_cell info;
72     afs_int32 i;
73 #if !defined(UKERNEL)
74     char cellstr[64];
75 #endif
76     afs_int32 gottdir = 0;
77     afs_int32 refresh = 0;
78
79     initialize_PT_error_table();
80     initialize_RXK_error_table();
81     initialize_ACFG_error_table();
82     initialize_KTC_error_table();
83
84 #if defined(UKERNEL)
85     if (!cell) {
86         cell = afs_LclCellName;
87     }
88 #else /* defined(UKERNEL) */
89     if (!cell) {
90         if (!tdir) 
91             tdir = afsconf_Open(confDir);
92         if (!tdir) {
93             if (confDir && strcmp(confDir, ""))
94                 fprintf(stderr,
95                         "%s: Could not open configuration directory: %s.\n",
96                         whoami, confDir);
97             else
98                 fprintf(stderr,
99                         "%s: No configuration directory specified.\n",
100                         whoami);
101             return -1;
102         }
103         gottdir = 1;
104
105         code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
106         if (code) {
107             fprintf(stderr,
108                      "libprot: Could not get local cell. [%d]\n", code);
109             return code;
110         }
111         cell = cellstr;
112     }
113 #endif /* defined(UKERNEL) */
114
115     if (tdir == NULL || strcmp(confDir, tconfDir) || strcmp(cell, tcell)) {
116         /*
117          * force re-evaluation.  we either don't have an afsconf_dir,
118          * the directory has changed or the cell has changed.
119          */
120         if (tdir && !gottdir) {
121             afsconf_Close(tdir);
122             tdir = (struct afsconf_dir *)NULL;
123         }
124         pruclient = (struct ubik_client *)NULL;
125         refresh = 1;
126     }
127
128     if (refresh) {
129         strncpy(tconfDir, confDir, sizeof(tconfDir));
130         strncpy(tcell, cell, sizeof(tcell));
131
132 #if defined(UKERNEL)
133         tdir = afs_cdir;
134 #else /* defined(UKERNEL) */
135         if (!gottdir)
136             tdir = afsconf_Open(confDir);
137         if (!tdir) {
138             if (confDir && strcmp(confDir, ""))
139                 fprintf(stderr,
140                         "libprot: Could not open configuration directory: %s.\n",
141                         confDir);
142             else
143                 fprintf(stderr,
144                         "libprot: No configuration directory specified.\n");
145             return -1;
146         }
147 #endif /* defined(UKERNEL) */
148
149         code = afsconf_GetCellInfo(tdir, cell, "afsprot", &info);
150         if (code) {
151             fprintf(stderr, "libprot: Could not locate cell %s in %s/%s\n",
152                     cell, confDir, AFSDIR_CELLSERVDB_FILE);
153             return code;
154         }
155     }
156
157     /* If we already have a client and it is at the security level we
158      * want, don't get a new one. Unless the security level is 2 in
159      * which case we will get one (and re-read the key file).
160      */
161     if (pruclient && (lastLevel == secLevel) && (secLevel != 2)) {
162         return 0;
163     }
164
165     code = rx_Init(0);
166     if (code) {
167         fprintf(stderr, "libprot:  Could not initialize rx.\n");
168         return code;
169     }
170
171     /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
172      * to force use of the KeyFile.  secLevel == 0 implies -noauth was
173      * specified. */
174     if (secLevel == 2) {
175         code = afsconf_GetLatestKey(tdir, 0, 0);
176         if (code) {
177             afs_com_err(whoami, code, "(getting key from local KeyFile)\n");
178         } else {
179             /* If secLevel is two assume we're on a file server and use
180              * ClientAuthSecure if possible. */
181             code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
182             if (code)
183                 afs_com_err(whoami, code, "(calling client secure)\n");
184         }
185     } else if (secLevel > 0) {
186         secFlags = 0;
187         if (secLevel > 1)
188             secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
189
190         code = afsconf_ClientAuthToken(&info, secFlags, &sc, &scIndex, NULL);
191         if (code) {
192             afs_com_err(whoami, code, "(getting token)");
193             if (secLevel > 1)
194                 return code;
195         }
196     }
197
198     if (sc == NULL) {
199         sc = rxnull_NewClientSecurityObject();
200         scIndex = 0;
201     }
202
203     if ((scIndex == 0) && (secLevel != 0))
204         fprintf(stderr,
205                 "%s: Could not get afs tokens, running unauthenticated\n",
206                 whoami);
207
208     memset(serverconns, 0, sizeof(serverconns));        /* terminate list!!! */
209     for (i = 0; i < info.numServers; i++)
210         serverconns[i] =
211             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
212                              info.hostAddr[i].sin_port, PRSRV, sc,
213                              scIndex);
214
215     code = ubik_ClientInit(serverconns, &pruclient);
216     if (code) {
217         afs_com_err(whoami, code, "ubik client init failed.");
218         return code;
219     }
220     lastLevel = scIndex;
221
222     code = rxs_Release(sc);
223     return code;
224 }
225
226 int
227 pr_End(void)
228 {
229     int code = 0;
230
231     if (pruclient) {
232         code = ubik_ClientDestroy(pruclient);
233         pruclient = 0;
234     }
235     return code;
236 }
237
238
239
240 int
241 pr_CreateUser(char name[PR_MAXNAMELEN], afs_int32 *id)
242 {
243     register afs_int32 code;
244
245     stolower(name);
246     if (*id) {
247         code = ubik_PR_INewEntry(pruclient, 0, name, *id, 0);
248         return code;
249     } else {
250         code = ubik_PR_NewEntry(pruclient, 0, name, 0, 0, id);
251         return code;
252     }
253
254 }
255
256 int 
257 pr_CreateGroup(char name[PR_MAXNAMELEN], char owner[PR_MAXNAMELEN], afs_int32 *id)
258 {
259     register afs_int32 code;
260     afs_int32 oid = 0;
261     afs_int32 flags = 0;
262
263     stolower(name);
264     if (owner) {
265         code = pr_SNameToId(owner, &oid);
266         if (code)
267             return code;
268         if (oid == ANONYMOUSID)
269             return PRNOENT;
270     }
271     flags |= PRGRP;
272     if (*id) {
273         code = ubik_PR_INewEntry(pruclient, 0, name, *id, oid);
274         return code;
275     } else {
276         code = ubik_PR_NewEntry(pruclient, 0, name, flags, oid, id);
277         return code;
278     }
279 }
280
281 int
282 pr_Delete(char *name)
283 {
284     register afs_int32 code;
285     afs_int32 id;
286
287     stolower(name);
288     code = pr_SNameToId(name, &id);
289     if (code)
290         return code;
291     if (id == ANONYMOUSID)
292         return PRNOENT;
293     code = ubik_PR_Delete(pruclient, 0, id);
294     return code;
295 }
296
297 int
298 pr_DeleteByID(afs_int32 id)
299 {
300     register afs_int32 code;
301
302     code = ubik_PR_Delete(pruclient, 0, id);
303     return code;
304 }
305
306 int
307 pr_AddToGroup(char *user, char *group)
308 {
309     register afs_int32 code;
310     namelist lnames;
311     idlist lids;
312
313     lnames.namelist_len = 2;
314     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
315     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
316     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
317     lids.idlist_val = 0;
318     lids.idlist_len = 0;
319     code = pr_NameToId(&lnames, &lids);
320     if (code)
321         goto done;
322     /* if here, still could be missing an entry */
323     if (lids.idlist_val[0] == ANONYMOUSID
324         || lids.idlist_val[1] == ANONYMOUSID) {
325         code = PRNOENT;
326         goto done;
327     }
328     code =
329         ubik_PR_AddToGroup(pruclient, 0, lids.idlist_val[0],
330                   lids.idlist_val[1]);
331   done:
332     if (lnames.namelist_val)
333         free(lnames.namelist_val);
334
335     xdr_free((xdrproc_t) xdr_idlist, &lids);
336     return code;
337 }
338
339 int
340 pr_RemoveUserFromGroup(char *user, char *group)
341 {
342     register afs_int32 code;
343     namelist lnames;
344     idlist lids;
345
346     lnames.namelist_len = 2;
347     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
348     strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN);
349     strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN);
350     lids.idlist_val = 0;
351     lids.idlist_len = 0;
352     code = pr_NameToId(&lnames, &lids);
353     if (code)
354         goto done;
355
356     if (lids.idlist_val[0] == ANONYMOUSID
357         || lids.idlist_val[1] == ANONYMOUSID) {
358         code = PRNOENT;
359         goto done;
360     }
361     code =
362         ubik_PR_RemoveFromGroup(pruclient, 0, lids.idlist_val[0],
363                   lids.idlist_val[1]);
364   done:
365     if (lnames.namelist_val)
366         free(lnames.namelist_val);
367
368     xdr_free((xdrproc_t) xdr_idlist, &lids);
369
370     return code;
371 }
372
373 int
374 pr_NameToId(namelist *names, idlist *ids)
375 {
376     register afs_int32 code;
377     register afs_int32 i;
378
379     for (i = 0; i < names->namelist_len; i++)
380         stolower(names->namelist_val[i]);
381     code = ubik_PR_NameToID(pruclient, 0, names, ids);
382     return code;
383 }
384
385 int
386 pr_SNameToId(char name[PR_MAXNAMELEN], afs_int32 *id)
387 {
388     namelist lnames;
389     idlist lids;
390     register afs_int32 code;
391
392     lids.idlist_len = 0;
393     lids.idlist_val = 0;
394     lnames.namelist_len = 1;
395     lnames.namelist_val = malloc(PR_MAXNAMELEN);
396     stolower(name);
397     strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN);
398     code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
399     if (lids.idlist_val) {
400         *id = *lids.idlist_val;
401         xdr_free((xdrproc_t) xdr_idlist, &lids);
402     }
403     if (lnames.namelist_val)
404         free(lnames.namelist_val);
405     return code;
406 }
407
408 int
409 pr_IdToName(idlist *ids, namelist *names)
410 {
411     register afs_int32 code;
412
413     code = ubik_PR_IDToName(pruclient, 0, ids, names);
414     return code;
415 }
416
417 int
418 pr_SIdToName(afs_int32 id, char name[PR_MAXNAMELEN])
419 {
420     namelist lnames;
421     idlist lids;
422     register afs_int32 code;
423
424     lids.idlist_len = 1;
425     lids.idlist_val = malloc(sizeof(afs_int32));
426     *lids.idlist_val = id;
427     lnames.namelist_len = 0;
428     lnames.namelist_val = 0;
429     code = ubik_PR_IDToName(pruclient, 0, &lids, &lnames);
430
431     if (lnames.namelist_val)
432         strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN);
433
434     if (lids.idlist_val)
435         free(lids.idlist_val);
436
437     xdr_free((xdrproc_t) xdr_namelist, &lnames);
438
439     return code;
440 }
441
442 int
443 pr_GetCPS(afs_int32 id, prlist *CPS)
444 {
445     register afs_int32 code;
446     afs_int32 over;
447
448     over = 0;
449     code = ubik_PR_GetCPS(pruclient, 0, id, CPS, &over);
450     if (code != PRSUCCESS)
451         return code;
452     if (over) {
453         /* do something about this, probably make a new call */
454         /* don't forget there's a hard limit in the interface */
455         fprintf(stderr, "membership list for id %d exceeds display limit\n",
456                 id);
457     }
458     return 0;
459 }
460
461 int
462 pr_GetCPS2(afs_int32 id, afs_int32 host, prlist *CPS)
463 {
464     register afs_int32 code;
465     afs_int32 over;
466
467     over = 0;
468     code = ubik_PR_GetCPS2(pruclient, 0, id, host, CPS, &over);
469     if (code != PRSUCCESS)
470         return code;
471     if (over) {
472         /* do something about this, probably make a new call */
473         /* don't forget there's a hard limit in the interface */
474         fprintf(stderr, "membership list for id %d exceeds display limit\n",
475                 id);
476     }
477     return 0;
478 }
479
480 int
481 pr_GetHostCPS(afs_int32 host, prlist *CPS)
482 {
483     register afs_int32 code;
484     afs_int32 over;
485
486     over = 0;
487     code = ubik_PR_GetHostCPS(pruclient, 0, host, CPS, &over);
488     if (code != PRSUCCESS)
489         return code;
490     if (over) {
491         /* do something about this, probably make a new call */
492         /* don't forget there's a hard limit in the interface */
493         fprintf(stderr,
494                 "membership list for host id %d exceeds display limit\n",
495                 host);
496     }
497     return 0;
498 }
499
500 int
501 pr_ListMembers(char *group, namelist *lnames)
502 {
503     register afs_int32 code;
504     afs_int32 gid;
505
506     code = pr_SNameToId(group, &gid);
507     if (code)
508         return code;
509     if (gid == ANONYMOUSID)
510         return PRNOENT;
511     code = pr_IDListMembers(gid, lnames);
512     return code;
513 }
514
515 int
516 pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP)
517 {
518     register afs_int32 code;
519     prlist alist;
520     idlist *lids;
521
522     alist.prlist_len = 0;
523     alist.prlist_val = 0;
524     code = ubik_PR_ListOwned(pruclient, 0, oid, &alist, moreP);
525     if (code)
526         return code;
527     if (*moreP == 1) {
528         /* Remain backwards compatible when moreP was a T/F bit */
529         fprintf(stderr, "membership list for id %d exceeds display limit\n",
530                 oid);
531         *moreP = 0;
532     }
533     lids = (idlist *) &alist;
534     code = pr_IdToName(lids, lnames);
535
536     xdr_free((xdrproc_t) xdr_prlist, &alist);
537
538     if (code)
539         return code;
540
541     return PRSUCCESS;
542 }
543
544 int
545 pr_IDListMembers(afs_int32 gid, namelist *lnames)
546 {
547     register afs_int32 code;
548     prlist alist;
549     idlist *lids;
550     afs_int32 over;
551
552     alist.prlist_len = 0;
553     alist.prlist_val = 0;
554     code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over);
555     if (code)
556         return code;
557     if (over) {
558         fprintf(stderr, "membership list for id %d exceeds display limit\n",
559                 gid);
560     }
561     lids = (idlist *) &alist;
562     code = pr_IdToName(lids, lnames);
563
564     xdr_free((xdrproc_t) xdr_prlist, &alist);
565
566     if (code)
567         return code;
568     return PRSUCCESS;
569 }
570
571 int
572 pr_ListEntry(afs_int32 id, struct prcheckentry *aentry)
573 {
574     register afs_int32 code;
575
576     code = ubik_PR_ListEntry(pruclient, 0, id, aentry);
577     return code;
578 }
579
580 afs_int32
581 pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex)
582 {
583     afs_int32 code;
584     prentries bulkentries;
585
586     *nentries = 0;
587     *entries = NULL;
588     *nextstartindex = -1;
589     bulkentries.prentries_val = 0;
590     bulkentries.prentries_len = 0;
591
592     code =
593         ubik_PR_ListEntries(pruclient, 0, flag, startindex,
594                   &bulkentries, nextstartindex);
595     *nentries = bulkentries.prentries_len;
596     *entries = bulkentries.prentries_val;
597     return code;
598 }
599
600 int
601 pr_CheckEntryByName(char *name, afs_int32 *id, char *owner, char *creator)
602 {
603     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
604     register afs_int32 code;
605     struct prcheckentry aentry;
606
607     code = pr_SNameToId(name, id);
608     if (code)
609         return code;
610     if (*id == ANONYMOUSID)
611         return PRNOENT;
612     code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry);
613     if (code)
614         return code;
615     /* this should be done in one RPC, but I'm lazy. */
616     code = pr_SIdToName(aentry.owner, owner);
617     if (code)
618         return code;
619     code = pr_SIdToName(aentry.creator, creator);
620     if (code)
621         return code;
622     return PRSUCCESS;
623 }
624
625 int
626 pr_CheckEntryById(char *name, afs_int32 id, char *owner, char *creator)
627 {
628     /* struct prcheckentry returns other things, which aren't useful to show at this time. */
629     register afs_int32 code;
630     struct prcheckentry aentry;
631
632     code = pr_SIdToName(id, name);
633     if (code)
634         return code;
635     if (id == ANONYMOUSID)
636         return PRNOENT;
637     code = ubik_PR_ListEntry(pruclient, 0, id, &aentry);
638     if (code)
639         return code;
640     /* this should be done in one RPC, but I'm lazy. */
641     code = pr_SIdToName(aentry.owner, owner);
642     if (code)
643         return code;
644     code = pr_SIdToName(aentry.creator, creator);
645     if (code)
646         return code;
647     return PRSUCCESS;
648 }
649
650 int
651 pr_ChangeEntry(char *oldname, char *newname, afs_int32 *newid, char *newowner)
652 {
653     register afs_int32 code;
654     afs_int32 id;
655     afs_int32 oid = 0;
656
657     code = pr_SNameToId(oldname, &id);
658     if (code)
659         return code;
660     if (id == ANONYMOUSID)
661         return PRNOENT;
662     if (newowner && *newowner) {
663         code = pr_SNameToId(newowner, &oid);
664         if (code)
665             return code;
666         if (oid == ANONYMOUSID)
667             return PRNOENT;
668     }
669     if (newid)
670         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid);
671     else
672         code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0);
673     return code;
674 }
675
676 int
677 pr_IsAMemberOf(char *uname, char *gname, afs_int32 *flag)
678 {
679     register afs_int32 code;
680     namelist lnames;
681     idlist lids;
682
683     stolower(uname);
684     stolower(gname);
685     lnames.namelist_len = 2;
686     lnames.namelist_val = malloc(2 * PR_MAXNAMELEN);
687     strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN);
688     strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN);
689     lids.idlist_val = 0;
690     lids.idlist_len = 0;
691     code = pr_NameToId(&lnames, &lids);
692     if (code) {
693         if (lnames.namelist_val)
694             free(lnames.namelist_val);
695         xdr_free((xdrproc_t) xdr_idlist, &lids);
696         return code;
697     }
698     code =
699         ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0],
700                   lids.idlist_val[1], flag);
701     if (lnames.namelist_val)
702         free(lnames.namelist_val);
703     xdr_free((xdrproc_t) xdr_idlist, &lids);
704     return code;
705 }
706
707 int
708 pr_ListMaxUserId(afs_int32 *mid)
709 {
710     register afs_int32 code;
711     afs_int32 gid;
712     code = ubik_PR_ListMax(pruclient, 0, mid, &gid);
713     return code;
714 }
715
716 int
717 pr_SetMaxUserId(afs_int32 mid)
718 {
719     register afs_int32 code;
720     afs_int32 flag = 0;
721     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
722     return code;
723 }
724
725 int
726 pr_ListMaxGroupId(afs_int32 *mid)
727 {
728     register afs_int32 code;
729     afs_int32 id;
730     code = ubik_PR_ListMax(pruclient, 0, &id, mid);
731     return code;
732 }
733
734 int
735 pr_SetMaxGroupId(afs_int32 mid)
736 {
737     register afs_int32 code;
738     afs_int32 flag = 0;
739
740     flag |= PRGRP;
741     code = ubik_PR_SetMax(pruclient, 0, mid, flag);
742     return code;
743 }
744
745 afs_int32
746 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers)
747 {
748     register afs_int32 code;
749
750     code =
751         ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups,
752                   nusers, 0, 0);
753     return code;
754 }