Add sources for C account creation programs
This commit is contained in:
parent
4ec2fceaca
commit
3d20172dad
|
@ -0,0 +1,4 @@
|
|||
*.o
|
||||
/addmember
|
||||
/addclub
|
||||
/config-test
|
|
@ -0,0 +1,20 @@
|
|||
CFLAGS ?= -ggdb -Wall -O2
|
||||
CFLAGS += -I../include
|
||||
LDAP := -lldap
|
||||
KADM := $(shell krb5-config --libs krb5 kadm-client)
|
||||
|
||||
LIBCEO := util.o common.o config.o parser.o ldap.o krb5.o kadm.o addhomedir.o
|
||||
|
||||
all: addmember addclub
|
||||
|
||||
clean:
|
||||
rm -f addmember addclub config-test *.o
|
||||
|
||||
addmember: $(LIBCEO) addmember.o
|
||||
$(CC) $(LDFLAGS) $(LDAP) $(KADM) $^ -o $@
|
||||
|
||||
addclub: $(LIBCEO) addclub.o
|
||||
$(CC) $(LDFLAGS) $(LDAP) $(KADM) $^ -o $@
|
||||
|
||||
config-test: config-test.o parser.o util.o
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
|
@ -0,0 +1,181 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "ldap.h"
|
||||
#include "krb5.h"
|
||||
#include "kadm.h"
|
||||
#include "addhomedir.h"
|
||||
|
||||
char *prog = NULL;
|
||||
char *user = NULL;
|
||||
int privileged = 0;
|
||||
|
||||
static int force = 0;
|
||||
static int no_notify = 0;
|
||||
|
||||
static char *name = NULL;
|
||||
static char *userid = NULL;
|
||||
|
||||
static struct option opts[] = {
|
||||
{ "force", 0, NULL, 'f' },
|
||||
{ "no-notify", 0, NULL, 'q' },
|
||||
{ NULL, 0, NULL, '\0' },
|
||||
};
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s userid clubname\n", prog);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void addclub() {
|
||||
int krb_ok, user_ok, group_ok, home_ok, quota_ok;
|
||||
int id;
|
||||
char homedir[1024];
|
||||
|
||||
logmsg("adding uid=%s cn=%s by %s", userid, name, user);
|
||||
|
||||
if (setreuid(0, 0))
|
||||
fatalpe("setreuid");
|
||||
|
||||
if (!force && getpwnam(userid) != NULL)
|
||||
deny("user %s already exists", userid);
|
||||
|
||||
ceo_krb5_init();
|
||||
ceo_ldap_init();
|
||||
ceo_kadm_init();
|
||||
|
||||
if (ceo_user_exists(userid))
|
||||
deny("user %s already exists in LDAP", userid);
|
||||
|
||||
if ((id = ceo_new_uid(member_min_id, member_max_id)) <= 0)
|
||||
fatal("no available uids in range [%d, %d]", member_min_id, member_max_id);
|
||||
|
||||
snprintf(homedir, sizeof(homedir), "%s/%s", club_home, userid);
|
||||
|
||||
krb_ok = ceo_del_princ(userid);
|
||||
if (!krb_ok)
|
||||
logmsg("successfully cleared principal for %s", userid);
|
||||
|
||||
user_ok = krb_ok || ceo_add_user(userid, users_base, "club", name, homedir,
|
||||
club_shell, id, NULL);
|
||||
if (!user_ok)
|
||||
logmsg("successfully created account for %s", userid);
|
||||
|
||||
group_ok = user_ok || ceo_add_group(userid, groups_base, id);
|
||||
if (!group_ok)
|
||||
logmsg("successfully created group for %s", userid);
|
||||
|
||||
home_ok = user_ok || ceo_create_home(homedir, id, id);
|
||||
if (!home_ok)
|
||||
logmsg("successfully created home directory for %s", userid);
|
||||
|
||||
quota_ok = user_ok || ceo_set_quota(quota_prototype, id);
|
||||
if (!quota_ok)
|
||||
logmsg("successfully set quota for %s", userid);
|
||||
|
||||
logmsg("done uid=%s", userid);
|
||||
|
||||
if (!no_notify && !user_ok) {
|
||||
int pid;
|
||||
int hkp[2];
|
||||
FILE *hkf;
|
||||
int status;
|
||||
|
||||
if (pipe(hkp))
|
||||
errorpe("pipe");
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
close(hkp[1]);
|
||||
dup2(hkp[0], 0);
|
||||
exit(execl(notify_hook, notify_hook, prog, user, userid, name, NULL));
|
||||
}
|
||||
|
||||
hkf = fdopen(hkp[1], "w");
|
||||
|
||||
if (group_ok)
|
||||
fprintf(hkf, "failed to create group\n");
|
||||
if (home_ok)
|
||||
fprintf(hkf, "failed to create home directory\n");
|
||||
if (quota_ok)
|
||||
fprintf(hkf, "failed to set quota\n");
|
||||
if (!group_ok && !home_ok && !quota_ok)
|
||||
fprintf(hkf, "all failures went undetected\n");
|
||||
|
||||
fclose(hkf);
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status))
|
||||
logmsg("hook %s exited with status %d", notify_hook, WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
logmsg("hook %s killed by signal %d", notify_hook, WTERMSIG(status));
|
||||
}
|
||||
|
||||
ceo_kadm_cleanup();
|
||||
ceo_ldap_cleanup();
|
||||
ceo_krb5_cleanup();
|
||||
|
||||
return !krb_ok && !user_ok && !group_ok && !home_ok && quota_ok;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int opt;
|
||||
|
||||
openlog(prog, 0, LOG_AUTHPRIV);
|
||||
|
||||
configure();
|
||||
|
||||
prog = basename(argv[0]);
|
||||
user = ceo_get_user();
|
||||
privileged = ceo_get_privileged();
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
if (!privileged)
|
||||
deny("not privileged enough to force");
|
||||
force = 1;
|
||||
break;
|
||||
case 'q':
|
||||
if (!privileged)
|
||||
deny("not privileged enough to suppress notifications");
|
||||
no_notify = 1;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
fatal("error parsing arguments");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 2)
|
||||
usage();
|
||||
|
||||
userid = argv[optind++];
|
||||
name = argv[optind++];
|
||||
|
||||
addclub();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "addhomedir.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
int ceo_create_home(char *homedir, uid_t uid, gid_t gid) {
|
||||
int mask;
|
||||
DIR *skel;
|
||||
struct dirent *skelent;
|
||||
|
||||
mask = umask(0);
|
||||
|
||||
if (mkdir(homedir, homedir_mode)) {
|
||||
errorpe("failed to create %s", homedir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
skel = opendir(skeleton_dir);
|
||||
if (!skel) {
|
||||
errorpe("failed to open %s", skeleton_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((skelent = readdir(skel))) {
|
||||
struct stat sb;
|
||||
char src[PATH_MAX], dest[PATH_MAX];
|
||||
|
||||
if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, ".."))
|
||||
continue;
|
||||
|
||||
snprintf(src, sizeof(src), "%s/%s", skeleton_dir, skelent->d_name);
|
||||
snprintf(dest, sizeof(dest), "%s/%s", homedir, skelent->d_name);
|
||||
lstat(src, &sb);
|
||||
|
||||
if (sb.st_uid || sb.st_gid) {
|
||||
warn("not creating %s due to ownership", dest);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
int bytes;
|
||||
char buf[4096];
|
||||
|
||||
int srcfd = open(src, O_RDONLY);
|
||||
if (srcfd == -1) {
|
||||
warnpe("open: %s", src);
|
||||
continue;
|
||||
}
|
||||
|
||||
int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777);
|
||||
if (destfd == -1) {
|
||||
warnpe("open: %s", dest);
|
||||
close(srcfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bytes = read(srcfd, buf, sizeof(buf));
|
||||
if (!bytes)
|
||||
break;
|
||||
if (bytes < 0) {
|
||||
warnpe("read");
|
||||
break;
|
||||
}
|
||||
if (write(destfd, buf, bytes) < 0) {
|
||||
warnpe("write");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fchown(destfd, uid, gid))
|
||||
errorpe("chown: %s", dest);
|
||||
|
||||
close(srcfd);
|
||||
close(destfd);
|
||||
} else if (S_ISDIR(sb.st_mode)) {
|
||||
if (mkdir(dest, sb.st_mode & 0777)) {
|
||||
warnpe("mkdir: %s", dest);
|
||||
continue;
|
||||
}
|
||||
if (chown(dest, uid, gid))
|
||||
errorpe("chown: %s", dest);
|
||||
} else if (S_ISLNK(sb.st_mode)) {
|
||||
char lnkdest[PATH_MAX];
|
||||
int bytes;
|
||||
bytes = readlink(src, lnkdest, sizeof(lnkdest));
|
||||
lnkdest[bytes] = '\0';
|
||||
if (bytes == -1) {
|
||||
warnpe("readlink: %s", src);
|
||||
continue;
|
||||
}
|
||||
if (symlink(lnkdest, dest)) {
|
||||
warnpe("symlink: %s", dest);
|
||||
continue;
|
||||
}
|
||||
if (lchown(dest, uid, gid))
|
||||
errorpe("lchown: %s", dest);
|
||||
} else {
|
||||
warn("not creating %s", dest);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(skel);
|
||||
|
||||
if (chown(homedir, uid, gid))
|
||||
errorpe("failed to chown %s", homedir);
|
||||
|
||||
umask(mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceo_set_quota(char *proto, int id) {
|
||||
char user[128];
|
||||
char *sqargs[] = { "setquota", "-a", "-p", proto, NULL, NULL };
|
||||
|
||||
snprintf(user, sizeof(user), "%d", id);
|
||||
sqargs[4] = user;
|
||||
|
||||
if (spawnv("/usr/sbin/setquota", sqargs)) {
|
||||
error("failed to set quota for %s", user);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
int ceo_create_home(char *, uid_t, gid_t);
|
||||
int ceo_set_quota(char *, int);
|
|
@ -0,0 +1,196 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "ldap.h"
|
||||
#include "krb5.h"
|
||||
#include "kadm.h"
|
||||
#include "addhomedir.h"
|
||||
|
||||
char *prog = NULL;
|
||||
char *user = NULL;
|
||||
int privileged = 0;
|
||||
|
||||
static int force = 0;
|
||||
static int no_notify = 0;
|
||||
|
||||
static int use_stdin = 0;
|
||||
|
||||
static char *name = NULL;
|
||||
static char *userid = NULL;
|
||||
static char *program = NULL;
|
||||
static char password[1024];
|
||||
|
||||
static struct option opts[] = {
|
||||
{ "force", 0, NULL, 'f' },
|
||||
{ "no-notify", 0, NULL, 'q' },
|
||||
{ "stdin", 0, NULL, 's' },
|
||||
{ NULL, 0, NULL, '\0' },
|
||||
};
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s userid realname [program]\n", prog);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void addmember() {
|
||||
int krb_ok, user_ok, group_ok, home_ok, quota_ok;
|
||||
int id;
|
||||
char homedir[1024];
|
||||
|
||||
logmsg("adding uid=%s cn=%s program=%s by %s", userid, name, program, user);
|
||||
|
||||
if (setreuid(0, 0))
|
||||
fatalpe("setreuid");
|
||||
|
||||
if (!force && getpwnam(userid) != NULL)
|
||||
deny("user %s already exists", userid);
|
||||
|
||||
if (ceo_read_password(password, sizeof(password), use_stdin))
|
||||
return;
|
||||
|
||||
ceo_krb5_init();
|
||||
ceo_ldap_init();
|
||||
ceo_kadm_init();
|
||||
|
||||
if (ceo_user_exists(userid))
|
||||
deny("user %s already exists in LDAP", userid);
|
||||
|
||||
if ((id = ceo_new_uid(member_min_id, member_max_id)) <= 0)
|
||||
fatal("no available uids in range [%d, %d]", member_min_id, member_max_id);
|
||||
|
||||
snprintf(homedir, sizeof(homedir), "%s/%s", member_home, userid);
|
||||
|
||||
krb_ok = ceo_del_princ(userid);
|
||||
krb_ok = krb_ok || ceo_add_princ(userid, password);
|
||||
if (!krb_ok)
|
||||
logmsg("successfully created principal for %s", userid);
|
||||
|
||||
user_ok = krb_ok || ceo_add_user(userid, users_base, "member", name, homedir,
|
||||
member_shell, id, "program", program, NULL);
|
||||
if (!user_ok)
|
||||
logmsg("successfully created account for %s", userid);
|
||||
|
||||
group_ok = user_ok || ceo_add_group(userid, groups_base, id);
|
||||
if (!group_ok)
|
||||
logmsg("successfully created group for %s", userid);
|
||||
|
||||
home_ok = user_ok || ceo_create_home(homedir, id, id);
|
||||
if (!home_ok)
|
||||
logmsg("successfully created home directory for %s", userid);
|
||||
|
||||
quota_ok = user_ok || ceo_set_quota(quota_prototype, id);
|
||||
if (!quota_ok)
|
||||
logmsg("successfully set quota for %s", userid);
|
||||
|
||||
logmsg("done uid=%s", userid);
|
||||
|
||||
if (!no_notify && !user_ok) {
|
||||
int pid;
|
||||
int hkp[2];
|
||||
FILE *hkf;
|
||||
int status;
|
||||
|
||||
if (pipe(hkp))
|
||||
errorpe("pipe");
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
close(hkp[1]);
|
||||
dup2(hkp[0], 0);
|
||||
exit(execl(notify_hook, notify_hook, prog, user, userid, name, program, NULL));
|
||||
}
|
||||
|
||||
hkf = fdopen(hkp[1], "w");
|
||||
|
||||
if (group_ok)
|
||||
fprintf(hkf, "failed to create group\n");
|
||||
if (home_ok)
|
||||
fprintf(hkf, "failed to create home directory\n");
|
||||
if (quota_ok)
|
||||
fprintf(hkf, "failed to set quota\n");
|
||||
if (!group_ok && !home_ok && !quota_ok)
|
||||
fprintf(hkf, "all failures went undetected\n");
|
||||
|
||||
fclose(hkf);
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status))
|
||||
logmsg("hook %s exited with status %d", notify_hook, WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
logmsg("hook %s killed by signal %d", notify_hook, WTERMSIG(status));
|
||||
}
|
||||
|
||||
ceo_kadm_cleanup();
|
||||
ceo_ldap_cleanup();
|
||||
ceo_krb5_cleanup();
|
||||
|
||||
return !krb_ok && !user_ok && !group_ok && !home_ok && quota_ok;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int opt;
|
||||
|
||||
openlog(prog, 0, LOG_AUTHPRIV);
|
||||
|
||||
configure();
|
||||
|
||||
prog = basename(argv[0]);
|
||||
user = ceo_get_user();
|
||||
privileged = ceo_get_privileged();
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
use_stdin = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (!privileged)
|
||||
deny("not privileged enough to force");
|
||||
force = 1;
|
||||
break;
|
||||
case 'q':
|
||||
if (!privileged)
|
||||
deny("not privileged enough to suppress notifications");
|
||||
no_notify = 1;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
fatal("error parsing arguments");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 2 && argc - optind != 3)
|
||||
usage();
|
||||
|
||||
userid = argv[optind++];
|
||||
name = argv[optind++];
|
||||
|
||||
if (argc - optind)
|
||||
program = argv[optind++];
|
||||
|
||||
addmember();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
int ceo_get_privileged() {
|
||||
int uid = getuid();
|
||||
|
||||
// root is privileged
|
||||
if (!uid)
|
||||
return 1;
|
||||
|
||||
if (privileged_group) {
|
||||
struct group *privgrp = getgrnam(privileged_group);
|
||||
int pgid;
|
||||
gid_t grps[128];
|
||||
int count, i;
|
||||
if (!privgrp)
|
||||
return 0;
|
||||
pgid = privgrp->gr_gid;
|
||||
|
||||
count = getgroups(sizeof(grps), grps);
|
||||
for (i = 0; i < count; i++)
|
||||
if (grps[i] == pgid)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *ceo_get_user() {
|
||||
struct passwd *pwent = getpwuid(getuid());
|
||||
if (pwent == NULL)
|
||||
fatal("could not determine user");
|
||||
return xstrdup(pwent->pw_name);
|
||||
}
|
||||
|
||||
void ceo_notify_hook(int argc, ...) {
|
||||
va_list args;
|
||||
char **argv;
|
||||
int i = 0;
|
||||
|
||||
va_start(args, argc);
|
||||
|
||||
argv = (char **)xmalloc(sizeof(char *) * (argc + 1));
|
||||
|
||||
while (i < argc)
|
||||
argv[i++] = va_arg(args, char *);
|
||||
|
||||
argv[i++] = NULL;
|
||||
spawnv(notify_hook, argv);
|
||||
|
||||
va_end(args);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
int ceo_get_privileged();
|
||||
char *ceo_get_user();
|
||||
void ceo_notify_hook(int, ...);
|
|
@ -0,0 +1,21 @@
|
|||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "util.h"
|
||||
|
||||
void config_var(const char *name, const char *value) {
|
||||
printf("%s = \"%s\"\n", name, value);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s filename\n\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_parse(argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "parser.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DEF_STR NULL
|
||||
#define DEF_LONG LONG_MIN
|
||||
|
||||
char *server_url = DEF_STR;
|
||||
|
||||
char *users_base = DEF_STR;
|
||||
char *groups_base = DEF_STR;
|
||||
|
||||
char *skeleton_dir = DEF_STR;
|
||||
char *quota_prototype = DEF_STR;
|
||||
char *homedir_prefix = DEF_STR;
|
||||
|
||||
char *member_home = DEF_STR;
|
||||
char *member_shell = DEF_STR;
|
||||
long member_min_id = DEF_LONG;
|
||||
long member_max_id = DEF_LONG;
|
||||
|
||||
char *club_home = DEF_STR;
|
||||
char *club_shell = DEF_STR;
|
||||
long club_min_id = DEF_LONG;
|
||||
long club_max_id = DEF_LONG;
|
||||
|
||||
char *notify_hook = DEF_STR;
|
||||
|
||||
char *realm = DEF_STR;
|
||||
|
||||
char *admin_principal = DEF_STR;
|
||||
char *admin_keytab = DEF_STR;
|
||||
|
||||
char *admin_bind_userid = DEF_STR;
|
||||
char *admin_bind_keytab = DEF_STR;
|
||||
|
||||
char *sasl_realm = DEF_STR;
|
||||
char *sasl_mech = DEF_STR;
|
||||
|
||||
char *privileged_group = DEF_STR;
|
||||
|
||||
long homedir_mode = DEF_LONG;
|
||||
long homedir_min_uid = DEF_LONG;
|
||||
|
||||
static char *strvarnames[] = { "server_url", "users_base", "admin_principal",
|
||||
"admin_keytab", "skeleton_dir", "quota_prototype", "homedir_prefix",
|
||||
"member_home", "member_shell", "club_home", "club_shell", "realm",
|
||||
"admin_bind_userid", "admin_bind_keytab", "groups_base",
|
||||
"privileged_group", "notify_hook", "sasl_realm", "sasl_mech" };
|
||||
static char **strvars[] = { &server_url, &users_base, &admin_principal,
|
||||
&admin_keytab, &skeleton_dir, "a_prototype, &homedir_prefix,
|
||||
&member_home, &member_shell, &club_home, &club_shell, &realm,
|
||||
&admin_bind_userid, &admin_bind_keytab, &groups_base,
|
||||
&privileged_group, ¬ify_hook, &sasl_realm, &sasl_mech };
|
||||
|
||||
static char *longvarnames[] = { "member_min_id", "member_max_id",
|
||||
"homedir_mode", "homedir_min_uid", "club_min_id", "club_max_id" };
|
||||
static long *longvars[] = { &member_min_id, &member_max_id, &homedir_mode,
|
||||
&homedir_min_uid, &club_min_id, &club_max_id };
|
||||
|
||||
void config_var(char *var, char *val) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(strvars)/sizeof(*strvars); i++) {
|
||||
if (!strcmp(var, strvarnames[i])) {
|
||||
if (!strvars[i])
|
||||
free(strvars[i]);
|
||||
*strvars[i] = xstrdup(val);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(longvars)/sizeof(*longvars); i++) {
|
||||
if (!strcmp(var, longvarnames[i])) {
|
||||
*longvars[i] = config_long(var, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void configure() {
|
||||
int i;
|
||||
|
||||
config_parse(CONFIG_FILE);
|
||||
|
||||
for (i = 0; i < sizeof(strvars)/sizeof(*strvars); i++) {
|
||||
if (*strvars[i] == DEF_STR)
|
||||
badconf("undefined string variable: %s", strvarnames[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(longvars)/sizeof(*longvars); i++) {
|
||||
if (*longvars[i] == DEF_LONG)
|
||||
badconf("undefined long variable: %s", longvarnames[i]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#define CONFIG_FILE "/etc/csc/accounts.cf"
|
||||
|
||||
extern char *server_url;
|
||||
extern char *users_base;
|
||||
extern char *groups_base;
|
||||
|
||||
extern char *admin_bind_dn;
|
||||
extern char *admin_bind_pw;
|
||||
|
||||
extern char *skeleton_dir;
|
||||
extern char *quota_prototype;
|
||||
extern char *homedir_prefix;
|
||||
|
||||
extern char *member_home;
|
||||
extern char *member_shell;
|
||||
extern long member_min_id;
|
||||
extern long member_max_id;
|
||||
|
||||
extern char *club_home;
|
||||
extern char *club_shell;
|
||||
extern long club_min_id;
|
||||
extern long club_max_id;
|
||||
|
||||
extern char *notify_hook;
|
||||
|
||||
extern long homedir_mode;
|
||||
extern long homedir_min_uid;
|
||||
|
||||
extern char *realm;
|
||||
|
||||
extern char *admin_principal;
|
||||
extern char *admin_keytab;
|
||||
|
||||
extern char *admin_bind_userid;
|
||||
extern char *admin_bind_keytab;
|
||||
|
||||
extern char *sasl_realm;
|
||||
extern char *sasl_mech;
|
||||
|
||||
extern char *privileged_group;
|
||||
|
||||
void configure();
|
|
@ -0,0 +1,66 @@
|
|||
#include <kadm5/admin.h>
|
||||
|
||||
#include "kadm.h"
|
||||
#include "krb5.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
extern char *prog;
|
||||
|
||||
static void *handle;
|
||||
|
||||
void ceo_kadm_init() {
|
||||
krb5_error_code retval;
|
||||
kadm5_config_params params;
|
||||
memset((void *) ¶ms, 0, sizeof(params));
|
||||
|
||||
retval = kadm5_init_with_skey(admin_principal, admin_keytab,
|
||||
KADM5_ADMIN_SERVICE, ¶ms, KADM5_STRUCT_VERSION,
|
||||
KADM5_API_VERSION_2, &handle);
|
||||
if (retval) {
|
||||
com_err(prog, retval, "while initializing kadm5");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ceo_kadm_cleanup() {
|
||||
kadm5_destroy(handle);
|
||||
}
|
||||
|
||||
int ceo_add_princ(char *user, char *password) {
|
||||
krb5_error_code retval;
|
||||
kadm5_principal_ent_rec princ;
|
||||
memset((void *) &princ, 0, sizeof(princ));
|
||||
|
||||
if ((retval = krb5_parse_name(context, user, &princ.principal))) {
|
||||
com_err(prog, retval, "while parsing principal name");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if ((retval = kadm5_create_principal(handle, &princ, KADM5_PRINCIPAL, password))) {
|
||||
com_err(prog, retval, "while creating principal");
|
||||
return retval;
|
||||
}
|
||||
|
||||
krb5_free_principal(context, princ.principal);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceo_del_princ(char *user) {
|
||||
krb5_error_code retval;
|
||||
krb5_principal princ;
|
||||
|
||||
if ((retval = krb5_parse_name(context, user, &princ))) {
|
||||
com_err(prog, retval, "while parsing principal name");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = kadm5_delete_principal(handle, princ);
|
||||
if (retval && retval != KADM5_UNK_PRINC) {
|
||||
com_err(prog, retval, "while deleting principal");
|
||||
return retval;
|
||||
}
|
||||
|
||||
krb5_free_principal(context, princ);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
void ceo_kadm_init();
|
||||
void ceo_kadm_cleanup();
|
||||
|
||||
int ceo_add_princ(char *, char *);
|
||||
int ceo_del_princ(char *);
|
|
@ -0,0 +1,149 @@
|
|||
#include <stdio.h>
|
||||
#include <krb5.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "krb5.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
extern char *prog;
|
||||
|
||||
krb5_context context;
|
||||
|
||||
static void com_err_hk(const char *whoami, long code, const char *fmt, va_list args) {
|
||||
char message[4096];
|
||||
char *msgp = message;
|
||||
|
||||
msgp += snprintf(msgp, sizeof(message) - 2 - (msgp - message), "%s ", error_message(code));
|
||||
if (msgp - message > sizeof(message) - 2)
|
||||
fatal("error message overflowed");
|
||||
|
||||
msgp += vsnprintf(msgp, sizeof(message) - 2 - (msgp - message), fmt, args);
|
||||
if (msgp - message > sizeof(message) - 2)
|
||||
fatal("error message overflowed");
|
||||
|
||||
*msgp++ = '\n';
|
||||
*msgp++ = '\0';
|
||||
|
||||
syslog(LOG_ERR, "%s", message);
|
||||
fprintf(stderr, "%s: %s", whoami, message);
|
||||
}
|
||||
|
||||
void ceo_krb5_init() {
|
||||
krb5_error_code retval;
|
||||
|
||||
set_com_err_hook(com_err_hk);
|
||||
|
||||
retval = krb5_init_context(&context);
|
||||
if (retval) {
|
||||
com_err(prog, retval, "while initializing krb5");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = krb5_set_default_realm(context, realm);
|
||||
if (retval) {
|
||||
com_err(prog, retval, "while setting default realm");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ceo_krb5_auth(char *principal, char *ktname) {
|
||||
krb5_error_code retval;
|
||||
krb5_creds creds;
|
||||
krb5_principal princ;
|
||||
krb5_keytab keytab;
|
||||
krb5_ccache cache;
|
||||
krb5_get_init_creds_opt options;
|
||||
|
||||
krb5_get_init_creds_opt_init(&options);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
|
||||
if ((retval = krb5_parse_name(context, principal, &princ))) {
|
||||
com_err(prog, retval, "while resolving user %s", admin_bind_userid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_cc_default(context, &cache))) {
|
||||
com_err(prog, retval, "while resolving credentials cache");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_kt_resolve(context, ktname, &keytab))) {
|
||||
com_err(prog, retval, "while resolving keytab %s", admin_bind_keytab);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_get_init_creds_keytab(context, &creds, princ, keytab, 0, NULL, &options))) {
|
||||
com_err(prog, retval, "while getting initial credentials");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_cc_initialize(context, cache, princ))) {
|
||||
com_err(prog, retval, "while initializing credentials cache");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_cc_store_cred(context, cache, &creds))) {
|
||||
com_err(prog, retval, "while storing credentials");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
krb5_free_cred_contents(context, &creds);
|
||||
krb5_kt_close(context, keytab);
|
||||
krb5_free_principal(context, princ);
|
||||
krb5_cc_close(context, cache);
|
||||
}
|
||||
|
||||
void ceo_krb5_deauth() {
|
||||
krb5_error_code retval;
|
||||
krb5_ccache cache;
|
||||
|
||||
if ((retval = krb5_cc_default(context, &cache))) {
|
||||
com_err(prog, retval, "while resolving credentials cache");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((retval = krb5_cc_destroy(context, cache))) {
|
||||
com_err(prog, retval, "while destroying credentials cache");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ceo_krb5_cleanup() {
|
||||
krb5_free_context(context);
|
||||
}
|
||||
|
||||
int ceo_read_password(char *password, unsigned int size, int use_stdin) {
|
||||
int tries = 0;
|
||||
unsigned int len;
|
||||
|
||||
do {
|
||||
if (use_stdin) {
|
||||
if (fgets(password, size, stdin) == NULL)
|
||||
fatal("eof while reading password");
|
||||
|
||||
size = strlen(password);
|
||||
|
||||
if (password[size - 1] == '\n')
|
||||
password[size - 1] = '\0';
|
||||
} else {
|
||||
len = size;
|
||||
int retval = krb5_read_password(context, "New password", "Confirm password", password, &len);
|
||||
if (retval == KRB5_LIBOS_PWDINTR) {
|
||||
error("interrupted");
|
||||
return -1;
|
||||
} else if (retval == KRB5_LIBOS_BADPWDMATCH) {
|
||||
fputs("Passwords do not match.\n", stderr);
|
||||
} else if (!password || !*password) {
|
||||
fputs("Please enter a password.\n", stderr);
|
||||
}
|
||||
}
|
||||
} while (++tries < 3 && !*password);
|
||||
|
||||
if (!*password) {
|
||||
error("maximum tries exceeded reading password");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include <krb5.h>
|
||||
|
||||
extern krb5_context context;
|
||||
|
||||
void ceo_krb5_init();
|
||||
void ceo_krb5_cleanup();
|
||||
|
||||
void ceo_krb5_auth(char *, char *);
|
||||
void ceo_krb5_deauth();
|
||||
|
||||
int ceo_read_password(char *, unsigned int, int);
|
|
@ -0,0 +1,286 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sasl/sasl.h>
|
||||
#include <ldap.h>
|
||||
#include <krb5.h>
|
||||
|
||||
#include "ldap.h"
|
||||
#include "krb5.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
extern char *prog;
|
||||
|
||||
LDAP *ld;
|
||||
|
||||
static void ldap_fatal(char *msg) {
|
||||
int errnum;
|
||||
char *errstr, *detail;
|
||||
|
||||
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &errnum);
|
||||
ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &detail);
|
||||
|
||||
errstr = ldap_err2string(errnum);
|
||||
|
||||
if (detail && *detail)
|
||||
fatal("%s: %s (%d): %s", msg, errstr, errnum, detail);
|
||||
else
|
||||
fatal("%s: %s (%d)", msg, errstr, errnum);
|
||||
}
|
||||
|
||||
static void ldap_err(char *msg) {
|
||||
int errnum;
|
||||
char *errstr, *detail;
|
||||
|
||||
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &errnum);
|
||||
ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &detail);
|
||||
|
||||
errstr = ldap_err2string(errnum);
|
||||
|
||||
if (detail && *detail)
|
||||
error("%s: %s (%d): %s", msg, errstr, errnum, detail);
|
||||
else
|
||||
error("%s: %s (%d)", msg, errstr, errnum);
|
||||
}
|
||||
|
||||
int ceo_add_group(char *cn, char *basedn, int no) {
|
||||
if (!cn || !basedn)
|
||||
fatal("addgroup: Invalid argument");
|
||||
|
||||
LDAPMod *mods[8];
|
||||
int i = -1;
|
||||
int ret = 0;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "objectClass";
|
||||
char *objectClasses[] = { "top", "group", "posixGroup", NULL };
|
||||
mods[i]->mod_values = objectClasses;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "cn";
|
||||
char *uids[] = { cn, NULL };
|
||||
mods[i]->mod_values = uids;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "gidNumber";
|
||||
char idno[16];
|
||||
snprintf(idno, sizeof(idno), "%d", no);
|
||||
char *gidNumbers[] = { idno, NULL };
|
||||
mods[i]->mod_values = gidNumbers;
|
||||
|
||||
mods[++i] = NULL;
|
||||
|
||||
char dn[1024];
|
||||
snprintf(dn, sizeof(dn), "cn=%s,%s", cn, basedn);
|
||||
|
||||
if (ldap_add_s(ld, dn, mods) != LDAP_SUCCESS) {
|
||||
ldap_err("addgroup");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (mods[i])
|
||||
free(mods[i++]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ceo_add_user(char *uid, char *basedn, char *objclass, char *cn, char *home, char *shell, int no, ...) {
|
||||
va_list args;
|
||||
|
||||
if (!uid || !basedn || !cn || !home || !shell)
|
||||
fatal("adduser: Invalid argument");
|
||||
|
||||
LDAPMod *mods[16];
|
||||
int i = -1;
|
||||
int ret = 0;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "objectClass";
|
||||
char *objectClasses[] = { "top", "account", "posixAccount", "shadowAccount", NULL, NULL };
|
||||
if (objclass != NULL)
|
||||
objectClasses[4] = objclass;
|
||||
mods[i]->mod_values = objectClasses;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "uid";
|
||||
char *uids[] = { uid, NULL };
|
||||
mods[i]->mod_values = uids;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "cn";
|
||||
char *cns[] = { cn, NULL };
|
||||
mods[i]->mod_values = cns;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "uidNumber";
|
||||
char idno[16];
|
||||
snprintf(idno, sizeof(idno), "%d", no);
|
||||
char *uidNumbers[] = { idno, NULL };
|
||||
mods[i]->mod_values = uidNumbers;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "gidNumber";
|
||||
mods[i]->mod_values = uidNumbers;
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = "homeDirectory";
|
||||
char *homeDirectory[] = { home, NULL };
|
||||
mods[i]->mod_values = homeDirectory;
|
||||
|
||||
va_start(args, no);
|
||||
char *attr;
|
||||
while ((attr = va_arg(args, char *))) {
|
||||
char *val = va_arg(args, char *);
|
||||
|
||||
if (!val || !*val)
|
||||
continue;
|
||||
|
||||
if (i == sizeof(mods) / sizeof(*mods) - 2) {
|
||||
error("too many attributes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mods[++i] = xmalloc(sizeof(LDAPMod));
|
||||
mods[i]->mod_op = LDAP_MOD_ADD;
|
||||
mods[i]->mod_type = attr;
|
||||
char *vals[] = { val, NULL };
|
||||
mods[i]->mod_values = vals;
|
||||
}
|
||||
|
||||
mods[++i] = NULL;
|
||||
|
||||
char dn[1024];
|
||||
snprintf(dn, sizeof(dn), "uid=%s,%s", uid, basedn);
|
||||
|
||||
if (ldap_add_s(ld, dn, mods) != LDAP_SUCCESS) {
|
||||
ldap_err("adduser");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (mods[i])
|
||||
free(mods[i++]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ceo_new_uid(int min, int max) {
|
||||
char filter[64];
|
||||
char *attrs[] = { LDAP_NO_ATTRS, NULL };
|
||||
LDAPMessage *res;
|
||||
int i;
|
||||
|
||||
for (i = min; i <= max; i++) {
|
||||
// id taken due to passwd
|
||||
if (getpwuid(i) != NULL)
|
||||
continue;
|
||||
|
||||
// id taken due to group
|
||||
if (getgrgid(i) != NULL)
|
||||
continue;
|
||||
|
||||
snprintf(filter, sizeof(filter), "(|(uidNumber=%d)(gidNumber=%d))", i, i);
|
||||
if (ldap_search_s(ld, users_base, LDAP_SCOPE_SUBTREE, filter, attrs, 1, &res) != LDAP_SUCCESS) {
|
||||
ldap_err("firstuid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int count = ldap_count_entries(ld, res);
|
||||
ldap_msgfree(res);
|
||||
|
||||
// id taken due to LDAP
|
||||
if (count)
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ceo_add_club(char *uid, char *cn) {
|
||||
int id = ceo_new_uid(club_min_id, club_max_id);
|
||||
|
||||
if (ceo_add_user(uid, users_base, "club", cn, club_home, club_shell, id, NULL))
|
||||
return -1;
|
||||
|
||||
if (ceo_add_group(uid, groups_base, id))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceo_user_exists(char *uid) {
|
||||
char *attrs[] = { LDAP_NO_ATTRS, NULL };
|
||||
LDAPMessage *msg = NULL;
|
||||
char filter[128];
|
||||
int count;
|
||||
|
||||
if (!uid)
|
||||
fatal("null uid");
|
||||
|
||||
snprintf(filter, sizeof(filter), "uid=%s", uid);
|
||||
|
||||
if (ldap_search_s(ld, users_base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg) != LDAP_SUCCESS) {
|
||||
ldap_err("user_exists");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = ldap_count_entries(ld, msg);
|
||||
ldap_msgfree(msg);
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in) {
|
||||
sasl_interact_t *interact = in;
|
||||
|
||||
while (interact->id != SASL_CB_LIST_END) {
|
||||
switch (interact->id) {
|
||||
|
||||
// GSSAPI doesn't require any callbacks
|
||||
|
||||
default:
|
||||
interact->result = "";
|
||||
interact->len = 0;
|
||||
}
|
||||
|
||||
interact++;
|
||||
}
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
void ceo_ldap_init() {
|
||||
int proto = LDAP_DEFAULT_PROTOCOL;
|
||||
|
||||
if (ldap_initialize(&ld, server_url) != LDAP_SUCCESS)
|
||||
ldap_fatal("ldap_initialize");
|
||||
|
||||
if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) != LDAP_OPT_SUCCESS)
|
||||
ldap_fatal("ldap_set_option");
|
||||
|
||||
ceo_krb5_auth(admin_bind_userid, admin_bind_keytab);
|
||||
|
||||
if (ldap_sasl_interactive_bind_s(ld, NULL, sasl_mech, NULL, NULL,
|
||||
LDAP_SASL_QUIET, &ldap_sasl_interact, NULL) != LDAP_SUCCESS)
|
||||
ldap_fatal("Bind failed");
|
||||
|
||||
ceo_krb5_deauth();
|
||||
}
|
||||
|
||||
void ceo_ldap_cleanup() {
|
||||
ldap_unbind(ld);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#define LDAP_DEFAULT_PROTOCOL LDAP_VERSION3
|
||||
|
||||
int ceo_add_user(char *, char *, char *, char *, char *, char *, int, ...);
|
||||
int ceo_add_group(char *, char *, int);
|
||||
int ceo_new_uid(int, int);
|
||||
|
||||
void ceo_ldap_init();
|
||||
void ceo_ldap_cleanup();
|
||||
|
||||
int ceo_user_exists(char *);
|
|
@ -0,0 +1,214 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
#define VAR_MAX 256
|
||||
|
||||
void config_var(const char *, const char *);
|
||||
|
||||
struct config_file {
|
||||
FILE *p;
|
||||
char *name;
|
||||
int line;
|
||||
struct config_file *parent;
|
||||
int comment;
|
||||
};
|
||||
|
||||
static void parse_config_file(char *, struct config_file *);
|
||||
static void parse_error(struct config_file *file, char *msg) {
|
||||
fatal("parse error on line %d of %s: %s", file->line, file->name, msg);
|
||||
}
|
||||
|
||||
static int parse_char(struct config_file *file) {
|
||||
int c = getc(file->p);
|
||||
if (c == '\n')
|
||||
(file->line)++;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void unparse_char(struct config_file *file, int c) {
|
||||
if (c == EOF)
|
||||
return;
|
||||
ungetc(c, file->p);
|
||||
if (c == '\n')
|
||||
(file->line)--;
|
||||
}
|
||||
|
||||
static void parse_name(struct config_file *file, char *name, size_t maxlen) {
|
||||
int len = 0;
|
||||
int c;
|
||||
|
||||
for (;;) {
|
||||
c = parse_char(file);
|
||||
|
||||
if (c == EOF || c == '\n') {
|
||||
unparse_char(file, c);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isalpha(c) && c != '_' && c != '-') {
|
||||
unparse_char(file, c);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == maxlen - 1)
|
||||
parse_error(file, "max name length exceeded");
|
||||
|
||||
name[len++] = c;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
parse_error(file, "expected name");
|
||||
|
||||
name[len++] = '\0';
|
||||
}
|
||||
|
||||
static void parse_value(struct config_file *file, char *value, size_t maxlen) {
|
||||
int len = 0;
|
||||
int quote = 0;
|
||||
int comment = 0;
|
||||
int space = 0;
|
||||
int c;
|
||||
|
||||
for (;;) {
|
||||
c = parse_char(file);
|
||||
|
||||
if (c == EOF || c == '\n')
|
||||
break;
|
||||
|
||||
if (c == '#')
|
||||
comment = 1;
|
||||
|
||||
if ((isspace(c) && !quote) || comment) {
|
||||
space = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"') {
|
||||
quote = ! quote;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == maxlen - space - 1)
|
||||
parse_error(file, "max value length exceeded");
|
||||
|
||||
if (space && len) {
|
||||
value[len++] = ' ';
|
||||
}
|
||||
|
||||
space = 0;
|
||||
value[len++] = c;
|
||||
}
|
||||
|
||||
if (quote)
|
||||
parse_error(file, "unbalanced quotes");
|
||||
|
||||
value[len++] = '\0';
|
||||
}
|
||||
|
||||
static void parse_include(struct config_file *file) {
|
||||
char path[PATH_MAX];
|
||||
struct config_file *parent = file->parent;
|
||||
|
||||
parse_value(file, path, sizeof(path));
|
||||
|
||||
while (parent != NULL) {
|
||||
if (!strcmp(file->name, parent->name))
|
||||
return;
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
parse_config_file(path, file);
|
||||
}
|
||||
|
||||
static void parse_config(struct config_file *file) {
|
||||
int c;
|
||||
int comment = 0;
|
||||
|
||||
char var[VAR_MAX];
|
||||
char value[VAR_MAX];
|
||||
|
||||
for (;;) {
|
||||
c = parse_char(file);
|
||||
|
||||
if (c == '\n') {
|
||||
comment = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == EOF)
|
||||
return;
|
||||
|
||||
if (isspace(c) | comment)
|
||||
continue;
|
||||
|
||||
if (c == '#') {
|
||||
comment = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
unparse_char(file, c);
|
||||
parse_name(file, var, sizeof(var));
|
||||
|
||||
if (!strcmp(var, "include")) {
|
||||
parse_include(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
c = parse_char(file);
|
||||
if (c == EOF || c == '\n')
|
||||
parse_error(file, "expected '=' before line end");
|
||||
if (c == '=')
|
||||
< |