steps to support modern FreeBSD. After Robert Watson <rwatson@FreeBSD.org> and Alec...
[arla.git] / milko / pts / ptserver.c
bloba3aab996f2c04c20b57546ac2db22203912e5507
1 /*
2 * Copyright (c) 1998, 1999, 2000 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
38 #include <sys/types.h>
39 #include <rx/rx.h>
40 #include <rx/rx_null.h>
42 #include <ports.h>
43 #include <ko.h>
44 #include <netinit.h>
45 #include <msecurity.h>
47 #ifdef KERBEROS
48 #ifdef HAVE_OPENSSL
49 #include <openssl/des.h>
50 #else
51 #include <des.h>
52 #endif
53 #ifdef HAVE_KRB4
54 #include <krb.h>
55 #endif
56 #ifdef HAVE_KRB5
57 #include <krb5.h>
58 #endif
59 #include <rxkad.h>
60 #endif
62 #include <err.h>
63 #include <assert.h>
64 #include <ctype.h>
65 #include <agetarg.h>
67 #ifndef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
71 #include <service.h>
73 #include <mlog.h>
74 #include <mdebug.h>
75 #include <mdb.h>
77 #include "pts.h"
78 #include "pts.ss.h"
79 #include "ptserver.h"
80 #include "pts.ss.h"
82 RCSID("$Id$");
84 static struct rx_service *prservice;
86 prheader_disk pr_header;
88 #define HEADERID PR_BADID
89 #define ILLEGAL_ID 0x40000000
90 #define ILLEGAL_GROUP 0x40000000
92 #define PRENTRY_DISK_SIZE (sizeof(prentry_disk) + PR_MAXGROUPS * sizeof(int32_t) + 16)
93 #define PRHEADER_DISK_SIZE (sizeof(prheader_disk) + 4 * PR_MAXGROUPS * sizeof(int32_t) + 16)
95 static void open_db (char *databaseprefix, int flags);
96 void prserver_close(void);
98 MDB *nametoid, *idtodata;
105 void
106 write_header(void)
108 int length = PRHEADER_DISK_SIZE;
109 struct mdb_datum key, value;
110 char pr_header_ydr[PRHEADER_DISK_SIZE];
111 int code;
113 char headerid = htonl(HEADERID);
115 if (ydr_encode_prheader_disk(&pr_header, pr_header_ydr, &length) == NULL)
116 err(1, "write_header");
118 key.data = &headerid;
119 key.length = sizeof(headerid);
121 value.data = pr_header_ydr;
122 value.length = PRHEADER_DISK_SIZE - length;
124 code = mdb_store(idtodata, &key, &value);
125 assert(code == 0);
132 void
133 read_header(void)
135 int length = PRHEADER_DISK_SIZE;
136 struct mdb_datum key, value;
137 char headerid = htonl(HEADERID);
138 int code;
140 key.data = &headerid;
141 key.length = sizeof(headerid);
143 code = mdb_fetch(idtodata, &key, &value);
144 assert(code == 0);
146 if (ydr_decode_prheader_disk(&pr_header, value.data, &length) == NULL)
147 err(1, "read_header");
154 char *
155 localize_name(const char *name, Bool *localp)
157 static prname localname;
158 char *tmp;
160 *localp = FALSE;
162 strlcpy(localname, name, sizeof(localname));
163 strlwr(localname);
165 tmp = strchr(localname, '@');
166 if (tmp)
167 if (!strcasecmp(tmp + 1, netinit_getrealm())) {
168 *tmp = '\0';
169 *localp = TRUE;
172 return localname;
179 static void
180 create_database(void)
182 pr_header.version = 0;
183 pr_header.headerSize = PRHEADER_DISK_SIZE;
184 pr_header.maxGroup = -210; /* XXX */
185 pr_header.maxID = 0;
186 /*XXX pr_header.orphan = 0;*/
187 pr_header.usercount = 0;
188 pr_header.groupcount = 0;
189 write_header();
193 * read_prentry(): Fetch data from db, return a classic pr_entry
197 read_prentry(int id, prentry *pr_entry)
199 prentry_disk disk_entry;
200 int status, i;
202 status = get_disk_entry(id, &disk_entry);
203 if (status)
204 return status;
206 memset(pr_entry, 0, sizeof(prentry));
208 pr_entry->flags = disk_entry.flags;
209 pr_entry->id = disk_entry.id;
210 pr_entry->cellid = disk_entry.cellid;
211 pr_entry->owner = disk_entry.owner;
212 pr_entry->creator = disk_entry.creator;
213 pr_entry->ngroups = disk_entry.ngroups;
214 strlcpy(pr_entry->name, disk_entry.name, sizeof(pr_entry->name));
216 if (disk_entry.owned.len > 0)
217 pr_entry->owned = disk_entry.owned.val[0];
219 for (i = 0; i < PRSIZE && i < disk_entry.entries.len; i++)
220 pr_entry->entries[i] = disk_entry.entries.val[i];
222 mlog_log (MDEBPRDB, "read_prentry id: %d owner: %d creator: %d name: %s",
223 pr_entry->id, pr_entry->owner,
224 pr_entry->creator, pr_entry->name);
226 return 0;
230 * store_disk_entry(): marshal prentry_disk and store in db
234 store_disk_entry(prentry_disk *entry)
236 char pr_entry_disk_ydr[PRENTRY_DISK_SIZE];
237 int length = PRENTRY_DISK_SIZE;
238 struct mdb_datum key, value;
239 int id;
241 mlog_log (MDEBPRDB, "store_disk_entry id: %d owner: %d creator: %d name: %s",
242 entry->id, entry->owner,
243 entry->creator, entry->name);
245 if (ydr_encode_prentry_disk((prentry_disk *) entry, pr_entry_disk_ydr, &length) == NULL)
246 err(1, "store_disk_entry");
248 id = htonl(entry->id);
249 key.data = &id;
250 key.length = sizeof(id);
252 value.data = pr_entry_disk_ydr;
253 value.length = PRENTRY_DISK_SIZE - length;
255 return mdb_store(idtodata, &key, &value);
259 * write_prentry(): update db with classic prentry
263 write_prentry(prentry *pr_entry)
265 prentry_disk disk_entry;
266 int i;
268 memset(&disk_entry, 0, sizeof(prentry_disk));
270 disk_entry.flags = pr_entry->flags;
271 disk_entry.id = pr_entry->id;
272 disk_entry.cellid = pr_entry->cellid;
273 disk_entry.owner = pr_entry->owner;
274 disk_entry.creator = pr_entry->creator;
275 disk_entry.ngroups = pr_entry->ngroups;
276 /* disk_entry.owned = pr_entry->owned; XXX */
277 strlcpy(disk_entry.name, pr_entry->name, sizeof(disk_entry.name));
279 for (i = 0; i < PRSIZE && i < pr_entry->count; i++)
280 disk_entry.entries.val[i] = pr_entry->entries[i];
282 disk_entry.entries.len = i;
284 return store_disk_entry(&disk_entry);
291 static int
292 write_name(prentry *pr_entry)
294 struct mdb_datum key, value;
295 int32_t id = htonl(pr_entry->id);
297 key.data = pr_entry->name;
298 key.length = strlen(pr_entry->name);
300 value.data = &id;
301 value.length = sizeof(id);
303 return mdb_store(nametoid, &key, &value);
310 static int
311 insert_entry(prentry *pr_entry)
313 char *pr_entry_disk_ydr;
314 int status;
315 int id;
317 char *name = pr_entry->name;
319 status = get_ydr_disk_entry(pr_entry->id, &pr_entry_disk_ydr);
320 if (status == 0)
321 return PREXIST;
322 if (status != PRNOENT)
323 return status;
325 status = conv_name_to_id(name, &id);
326 if (status == 0)
327 return PREXIST;
328 if (status != PRNOENT)
329 return status;
331 status = write_name(pr_entry);
332 if (status)
333 return status;
335 return write_prentry(pr_entry);
337 /* XXX: update owned and nextOwned */
338 /* XXX update header */
339 /* write_header(); */
347 create_group(const char *name,
348 int32_t id,
349 int32_t owner,
350 int32_t creator)
352 int status;
353 prentry pr_entry;
355 memset(&pr_entry, 0, sizeof(pr_entry));
356 pr_entry.flags = PRGRP;
357 pr_entry.id = id;
358 pr_entry.owner = owner;
359 pr_entry.creator = creator;
360 strlcpy(pr_entry.name, name, PR_MAXNAMELEN);
362 status = insert_entry(&pr_entry);
363 if (status)
364 return status;
366 return 0;
374 create_user(const char *name,
375 int32_t id,
376 int32_t owner,
377 int32_t creator)
379 int status;
380 prentry pr_entry;
382 memset(&pr_entry, 0, sizeof(pr_entry));
383 pr_entry.flags = 0;
384 pr_entry.id = id;
385 pr_entry.owner = owner;
386 pr_entry.creator = creator;
387 strlcpy(pr_entry.name, name, PR_MAXNAMELEN);
389 status = insert_entry(&pr_entry);
390 if (status)
391 return status;
393 return 0;
401 addtogroup (int32_t uid, int32_t gid)
403 prentry_disk uid_entry;
404 prentry_disk gid_entry;
405 int error, i, tmp1, tmp2;
407 mlog_log (MDEBPRDB, "addtogroup");
409 error = get_disk_entry(uid, &uid_entry);
410 if (error)
411 return error;
413 error = get_disk_entry(gid, &gid_entry);
414 if (error)
415 return error;
417 if (uid_entry.entries.len >= (PR_MAXGROUPS - 1)
418 || gid_entry.entries.len >= (PR_MAXLIST - 1))
419 return PRNOENT;
421 i = 0;
422 while (uid_entry.entries.val[i] < gid && i < uid_entry.entries.len)
423 i++;
425 tmp1 = gid;
426 for (; i < uid_entry.entries.len; i++) {
427 tmp2 = uid_entry.entries.val[i];
428 uid_entry.entries.val[i] = tmp1;
429 tmp1 = tmp2;
431 uid_entry.entries.val[uid_entry.entries.len] = tmp1;
432 uid_entry.entries.len++;
434 i = 0;
435 while (gid_entry.entries.val[i] < uid && i < gid_entry.entries.len)
436 i++;
438 tmp1 = uid;
439 for (; i < gid_entry.entries.len; i++) {
440 tmp2 = gid_entry.entries.val[i];
441 gid_entry.entries.val[i] = tmp1;
442 tmp1 = tmp2;
444 gid_entry.entries.val[gid_entry.entries.len] = tmp1;
445 gid_entry.entries.len++;
447 if ((error = store_disk_entry(&uid_entry)) != 0)
448 return error;
450 if ((error = store_disk_entry(&gid_entry)) != 0)
451 return error;
453 return 0;
461 removefromgroup (int32_t uid, int32_t gid)
463 prentry_disk uid_entry;
464 prentry_disk gid_entry;
465 int error, i;
467 mlog_log (MDEBPRDB, "removefromgroup");
469 error = get_disk_entry(uid, &uid_entry);
470 if (error)
471 return error;
473 error = get_disk_entry(gid, &gid_entry);
474 if (error)
475 return error;
478 i = 0;
479 while (uid_entry.entries.val[i] < gid && i < uid_entry.entries.len)
480 i++;
482 if (uid_entry.entries.val[i] != gid)
483 return PRNOENT;
485 for (i++; i < uid_entry.entries.len; i++)
486 uid_entry.entries.val[i - 1] = uid_entry.entries.val[i];
488 uid_entry.entries.len--;
490 i = 0;
491 while (gid_entry.entries.val[i] < uid && i < gid_entry.entries.len)
492 i++;
494 if (gid_entry.entries.val[i] != uid)
495 return PRNOENT;
497 for (i++; i < gid_entry.entries.len; i++)
498 gid_entry.entries.val[i - 1] = gid_entry.entries.val[i];
500 gid_entry.entries.len--;
502 /* XXX may leave database inconsistent ?? */
504 if ((error = store_disk_entry(&uid_entry)) != 0)
505 return error;
507 if ((error = store_disk_entry(&gid_entry)) != 0)
508 return error;
510 return 0;
519 listelements (int32_t id, prlist *elist, Bool default_id_p)
521 prentry_disk disk_entry;
522 int i = 0, error;
524 error = get_disk_entry(id, &disk_entry);
525 if (error)
526 return error;
528 if (default_id_p)
529 elist->len = disk_entry.entries.len + 3;
530 else
531 elist->len = disk_entry.entries.len;
533 elist->val = malloc(sizeof(*elist->val) * elist->len);
534 if (elist->val == NULL)
535 return ENOMEM; /* XXX */
538 /* XXX should be sorted */
540 for (i = 0; i < disk_entry.entries.len; i++)
541 elist->val[i] = disk_entry.entries.val[i];
543 if (default_id_p) {
544 elist->val[i] = id;
545 elist->val[++i] = PR_ANYUSERID;
546 elist->val[++i] = PR_AUTHUSERID;
549 return 0;
557 get_ydr_disk_entry(int id, char **buf)
559 struct mdb_datum key, value;
560 int status;
562 id = htonl(id);
564 key.data = &id;
565 key.length = sizeof(id);
567 status = mdb_fetch(idtodata, &key, &value);
568 if (status == ENOENT)
569 return PRNOENT;
571 *buf = value.data;
573 return status;
581 get_disk_entry(int id, prentry_disk *entry)
583 char *pr_entry_disk_ydr;
584 int length = PRENTRY_DISK_SIZE; /* XXX maxsize in mdb??? */
585 int status;
587 status = get_ydr_disk_entry(id, &pr_entry_disk_ydr);
588 if (status)
589 return status;
591 if (ydr_decode_prentry_disk(entry, pr_entry_disk_ydr, &length) == NULL)
592 err(1, "get_disk_entry");
594 return status;
602 conv_name_to_id(const char *name, int *id)
604 struct mdb_datum key, value;
605 int status;
607 key.data = strdup(name); /*XXX*/
608 key.length = strlen(name);
610 status = mdb_fetch(nametoid, &key, &value);
611 if (status == ENOENT)
612 status = PRNOENT;
613 else
614 *id = ntohl(*((int *)value.data));
616 free(key.data);
618 return status;
626 conv_id_to_name(int id, char *name)
628 prentry pr_entry;
629 int status;
631 status = read_prentry(id, &pr_entry);
632 if (status)
633 return status;
634 strlcpy(name, pr_entry.name, PR_MAXNAMELEN);
635 return 0;
643 next_free_group_id(int *id)
645 pr_header.maxGroup--; /* XXX */
646 if (pr_header.maxGroup == ILLEGAL_GROUP) {
647 pr_header.maxGroup++;
648 return -1;
651 write_header();
653 *id = pr_header.maxGroup;
654 return 0;
662 next_free_user_id(int *id)
664 pr_header.maxID++; /* XXX */
665 if (pr_header.maxID == ILLEGAL_ID) {
666 pr_header.maxID--;
667 return -1;
670 write_header();
672 *id = pr_header.maxID;
673 return 0;
680 static void
681 open_db (char *databaseprefix, int flags)
683 char database[MAXPATHLEN];
685 if (databaseprefix == NULL)
686 databaseprefix = MILKO_SYSCONFDIR;
688 snprintf (database, sizeof(database), "%s/pr_idtodata",
689 databaseprefix);
691 mlog_log (MDEBPR, "Loading db from file %s\n", database);
693 idtodata = mdb_open(database, flags, 0600);
694 if (idtodata == NULL)
695 err(1, "failed open (%s)", database);
698 snprintf (database, sizeof(database), "%s/pr_nametoid",
699 databaseprefix);
701 mlog_log (MDEBPR, "Loading db from file %s\n", database);
703 nametoid = mdb_open(database, flags, 0600);
704 if (nametoid == NULL)
705 err(1, "failed open (%s)", database);
708 void
709 prserver_close(void)
711 mdb_close(idtodata);
712 mdb_close(nametoid);
715 #ifndef O_BINARY
716 #define O_BINARY 0
717 #endif
723 static int
724 prserver_create (char *databaseprefix)
726 int status;
728 open_db (databaseprefix, O_RDWR|O_CREAT|O_EXCL|O_BINARY);
730 printf ("Creating a new pr-database.\n");
731 create_database();
733 #define M(N,I,O,G) \
734 do { \
735 status = create_group((N), (I), (O), (G)); \
736 if (status) \
737 errx (1, "failed when creating %s with error %d", \
738 (N), status); \
739 } while (0)
741 M("system:administrators", PR_SYSADMINID, PR_SYSADMINID, PR_SYSADMINID);
742 M("system:anyuser", PR_ANYUSERID, PR_SYSADMINID, PR_SYSADMINID);
743 M("system:authuser", PR_AUTHUSERID, PR_SYSADMINID, PR_SYSADMINID);
744 M("anonymous", PR_ANONYMOUSID, PR_SYSADMINID, PR_SYSADMINID);
746 #undef M
748 prserver_close();
750 return 0;
757 static int
758 prserver_init(char *databaseprefix)
760 open_db(databaseprefix, O_RDWR|O_BINARY);
761 read_header();
763 return 0;
770 static char *cell = NULL;
771 static char *realm = NULL;
772 static char *srvtab_file = NULL;
773 static char *log_file = "syslog";
774 static char *debug_levels = NULL;
775 static int no_auth = 0;
776 static int do_help = 0;
777 static char *databasedir = NULL;
778 static int do_create = 0;
780 static struct agetargs args[] = {
781 {"cell", 0, aarg_string, &cell, "what cell to use"},
782 {"realm", 0, aarg_string, &realm, "what realm to use"},
783 {"debug", 'd', aarg_string, &debug_levels, "debug level"},
784 {"log", 'l', aarg_string, &log_file,
785 "where to write log (stderr, syslog (default), or path to file)"},
786 {"srvtab", 0, aarg_string, &srvtab_file, "what srvtab to use"},
787 {"noauth", 0, aarg_flag, &no_auth, "disable authentication checks"},
788 {"help", 'h', aarg_flag, &do_help, "help"},
789 {"dbdir", 0, aarg_string, &databasedir, "where to store the db"},
790 {"create", 0, aarg_flag, &do_create, "create new database"},
791 { NULL, 0, aarg_end, NULL }
798 static void
799 usage(int exit_code)
801 aarg_printusage (args, NULL, "", AARG_GNUSTYLE);
802 exit (exit_code);
810 main(int argc, char **argv)
812 int optind = 0;
813 int ret;
814 Log_method *method;
816 setprogname (argv[0]);
818 if (agetarg (args, argc, argv, &optind, AARG_GNUSTYLE)) {
819 usage (1);
822 argc -= optind;
823 argv += optind;
825 if (argc) {
826 printf("unknown option %s", *argv);
827 return 1;
830 if (do_help)
831 usage(0);
833 if (no_auth)
834 sec_disable_superuser_check ();
836 method = log_open (getprogname(), log_file);
837 if (method == NULL)
838 errx (1, "log_open failed");
839 cell_init(0, method);
840 ports_init();
842 printf ("ptserver booting");
844 mlog_loginit (method, milko_deb_units, MDEFAULT_LOG);
846 if (debug_levels)
847 mlog_log_set_level (debug_levels);
849 if (cell)
850 cell_setthiscell (cell);
852 network_kerberos_init (srvtab_file);
854 if (do_create) {
855 prserver_create (databasedir);
856 return 0;
859 ret = prserver_init(databasedir);
860 if (ret)
861 errx (1, "prserver_init: error %d", ret);
863 ret = network_init(htons(afsprport), "pr", PR_SERVICE_ID,
864 PR_ExecuteRequest, &prservice, realm);
865 if (ret)
866 errx (1, "network_init returned %d", ret);
868 mlog_log (MDEBWARN, "started");
870 rx_SetMaxProcs(prservice,5) ;
871 rx_StartServer(1) ;
873 abort();
874 return 0;