/* Copyright (C) 1999-2004 IC & S dbmail@ic-s.nl This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Id: user.c 1712 2005-03-26 20:23:18Z aaron $ * This is the dbmail-user program * It makes adding users easier */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "user.h" #include "auth.h" #include #include #include #include #include "dbmail.h" #include "list.h" #include "debug.h" #include "db.h" #include #include #include /* for pid_t */ #include /* for getpid() */ #include "dm_getopt.h" #ifdef HAVE_CRYPT_H #include #endif #include "dbmd5.h" char *configFile = DEFAULT_CONFIG_FILE; #define SHADOWFILE "/etc/shadow" char *getToken(char **str, const char *delims); char csalt[] = "........"; char *bgetpwent(const char *filename, const char *name); char *cget_salt(void); /* database login data */ extern db_param_t _db_params; /* valid characters for passwd/username */ const char ValidChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" "_.!@#$%^&*()-+=~[]{}<>:;\\/"; /* Loudness and assumptions. */ int yes_to_all = 0; int no_to_all = 0; int verbose = 0; /* Don't be helpful. */ int quiet = 0; /* Don't print errors. */ int reallyquiet = 0; #define qprintf(fmt, args...) \ (quiet ? 0 : printf(fmt, ##args) ) #define qerrorf(fmt, args...) \ (reallyquiet ? 0 : fprintf(stderr, fmt, ##args) ) #define null_strncpy(dst, src, len) \ (src ? strncpy(dst, src, len) : 0 ) #define null_crypt(src, dst) \ (src ? crypt(src, dst) : "" ) struct change_flags { unsigned int newuser : 1; unsigned int newmaxmail : 1; unsigned int newclientid : 1; unsigned int newpasswd : 1; unsigned int newpasswdfile : 1; unsigned int newpasswdstdin : 1; unsigned int newpasswdshadow : 1; }; /* The prodigious use of const ensures that programming * mistakes inside of these functions don't cause us to * use incorrect values when calling auth_ and db_ internals. * */ /* Core operations */ int do_add(const char * const user, const char * const password, const char * const enctype, const u64_t maxmail, const u64_t clientid, struct list * const alias_add, struct list * const alias_del); int do_delete(const u64_t useridnr, const char * const user); int do_show(const char * const user); int do_empty(const u64_t useridnr); /* Change operations */ int do_username(const u64_t useridnr, const char *newuser); int do_maxmail(const u64_t useridnr, const u64_t maxmail); int do_clientid(const u64_t useridnr, const u64_t clientid); int do_password(const u64_t useridnr, const char * const password, const char * const enctype); int do_aliases(const u64_t useridnr, struct list * const alias_add, struct list * const alias_del); /* External forwards */ int do_forwards(const char *alias, const u64_t clientid, struct list * const fwds_add, struct list * const fwds_del); /* Helper functions */ int is_valid(const char * const str); u64_t strtomaxmail(const char * const str); int mkpassword(const char * const user, const char * const passwd, const char * const passwdtype, const char * const passwdfile, char ** password, char ** enctype); int do_showhelp(void) { printf("*** dbmail-users ***\n"); printf("Use this program to manage your DBMail users.\n"); printf("See the man page for more info. Modes of operation:\n\n"); // add, flush, delete, change, modify, password, alias, forward, list printf(" -a user add a user\n"); printf(" -d user delete a user\n"); printf(" -c user change details for a user\n"); printf(" -e user empty all mailboxes for a user\n"); printf(" -l uspec list information for matching users\n"); printf(" -x alias create an external forwarding address\n"); // printf(" -i enter an interactive user management console\n"); printf("\nSummary of options for all modes:\n"); printf(" -w passwd specify user's password on the command line\n"); printf(" -W [file] read from a file or prompt for a user's password\n"); printf(" -p pwtype password type may be one of the following:\n" " plaintext, crypt, md5-hash, md5-digest,\n" " crypt-raw, md5-hash-raw, md5-digest-raw\n"); printf(" -P [file] pull encrypted password from the shadow file\n"); printf(" -u user new username (only useful for -c, change)\n"); printf(" -g client assign the user to a client\n"); printf(" -m max set the maximum mail quota in B,\n" " K, or M, default in bytes\n" " specify 0 to remove any mail quota limits\n"); printf(" -s alia.. adds a list of recipient aliases\n"); printf(" -S alia.. removes a list of recipient aliases (wildcards supported)\n"); printf(" -t fwds.. adds a list of deliver-to forwards\n"); printf(" -T fwds.. removes a list of deliver-to forwards (wildcards supported)\n"); printf("\nCommon options for all DBMail utilities:\n"); printf(" -f file specify an alternative config file\n"); printf(" -q quietly skip interactive prompts\n" " use twice to suppress error messages\n"); /* printf(" -n show the intended action but do not perform it, no to all\n");*/ /* printf(" -y perform all proposed actions, as though yes to all\n");*/ printf(" -v verbose details\n"); printf(" -V show the version\n"); printf(" -h show this help message\n"); return 0; } int main(int argc, char *argv[]) { int opt = 0, opt_prev = 0; int show_help = 0; int result = 0, mode = 0, mode_toomany = 0; char *user = NULL, *newuser = NULL, *userspec = NULL, *alias = NULL; char *passwd = NULL, *passwdtype = NULL, *passwdfile = NULL; char *password = NULL, *enctype = NULL; u64_t useridnr = 0, clientid = 0, maxmail = 0; struct list alias_add, alias_del, fwds_add, fwds_del; struct change_flags change_flags; size_t len = 0; list_init(&alias_add); list_init(&alias_del); list_init(&fwds_add); list_init(&fwds_del); openlog(PNAME, LOG_PID, LOG_MAIL); setvbuf(stdout, 0, _IONBF, 0); /* Set all changes to false. */ memset(&change_flags, 0, sizeof(change_flags)); /* get options */ dm_opterr = 0; /* suppress error message from getopt() */ while ((opt = dm_getopt(argc, argv, "-a:d:c:e:l::x:" /* Major modes */ "W::w:P::p:u:g:m:t:s:S:T:" /* Minor options */ "i" "f:qnyvVh" /* Common options */ )) != -1) { /* The initial "-" of optstring allows unaccompanied * options and reports them as the optarg to opt 1 (not '1') */ if (opt == 1) opt = opt_prev; opt_prev = opt; switch (opt) { /* Major modes of operation * (exactly one of these is required) */ case 'a': case 'd': case 'c': case 'e': if (mode) mode_toomany = 1; mode = opt; if (dm_optarg && strlen(dm_optarg)) user = dm_strdup(dm_optarg); break; case 'x': if (mode) mode_toomany = 1; mode = opt; if (dm_optarg && strlen(dm_optarg)) alias = dm_strdup(dm_optarg); break; case 'l': /* It seems that the optional argument may * be passed as a second instance of this flag. */ if (mode != 0 && mode != 'l') mode_toomany = 1; mode = opt; if (dm_optarg && strlen(dm_optarg)) userspec = dm_strdup(dm_optarg); break; case 'i': printf("Interactive console is not supported in this release.\n"); return 1; /* Minor options */ case 'w': change_flags.newpasswd = 1; passwd = dm_strdup(dm_optarg); break; case 'W': change_flags.newpasswd = 1; if (dm_optarg && strlen(dm_optarg)) { passwdfile = dm_strdup(dm_optarg); change_flags.newpasswdfile = 1; } else { change_flags.newpasswdstdin = 1; } break; case 'u': change_flags.newuser = 1; newuser = dm_strdup(dm_optarg); break; case 'p': if (!passwdtype) passwdtype = dm_strdup(dm_optarg); // else // Complain about only one type allowed. break; case 'P': change_flags.newpasswdshadow = 1; if (dm_optarg && strlen(dm_optarg)) passwdfile = dm_strdup(dm_optarg); else passwdfile = SHADOWFILE; passwdtype = "shadow"; break; case 'g': change_flags.newclientid = 1; clientid = strtoull(dm_optarg, NULL, 10); break; case 'm': change_flags.newmaxmail = 1; maxmail = strtomaxmail(dm_optarg); break; case 's': // Add this item to the user's aliases. if (dm_optarg && (len = strlen(dm_optarg))) list_nodeadd(&alias_add, dm_optarg, len+1); break; case 'S': // Delete this item from the user's aliases. if (dm_optarg && (len = strlen(dm_optarg))) list_nodeadd(&alias_del, dm_optarg, len+1); break; case 't': // Add this item to the alias's forwards. if (dm_optarg && (len = strlen(dm_optarg))) list_nodeadd(&fwds_add, dm_optarg, len+1); break; case 'T': // Delete this item from the alias's forwards. if (dm_optarg && (len = strlen(dm_optarg))) list_nodeadd(&fwds_del, dm_optarg, len+1); break; /* Common options */ case 'f': if (dm_optarg && strlen(dm_optarg) > 0) configFile = dm_optarg; else { qerrorf("dbmail-users: -f requires a filename\n\n"); result = 1; } break; case 'h': show_help = 1; break; case 'n': printf("-n option is not supported in this " "release.\n"); return 1; case 'y': printf("-y option is not supported in this " "release.\n"); return 1; case 'q': /* If we get q twice, be really quiet! */ if (quiet) reallyquiet = 1; if (!verbose) quiet = 1; break; case 'v': if (!quiet) verbose = 1; break; case 'V': /* Show the version and return non-zero. */ printf("DBMail: dbmail-users\n" "Version: %s\n" "$Revision: 1712 $\n" "Copyright: %s\n", VERSION, COPYRIGHT); result = 1; break; default: /* printf("unrecognized option [%c], continuing...\n",optopt); */ break; } /* If there's a non-negative return code, * it's time to free memory and bail out. */ if (result) goto freeall; } /* If nothing is happening, show the help text. */ if (!mode || mode_toomany || show_help) { do_showhelp(); result = 1; goto freeall; } /* read the config file */ ReadConfig("DBMAIL", configFile); SetTraceLevel("DBMAIL"); GetDBParams(&_db_params); /* open database connection */ qprintf("Opening connection to database...\n"); if (db_connect() != 0) { qerrorf ("Failed. Could not connect to database (check log)\n"); result = -1; goto freeall; } /* open authentication connection */ qprintf("Opening connection to authentication...\n"); if (auth_connect() != 0) { qerrorf ("Failed. Could not connect to authentication (check log)\n"); result = -1; goto freeall; } if (db_check_version() != 0) { qerrorf ("Failed. You need to upgrade your database.\n"); result = -1; goto freeall; } qprintf("Ok. Connected\n"); //configure_debug(TRACE_ERROR, 1, 0); switch (mode) { case 'c': case 'd': case 'e': /* Verify the existence of this user */ if (auth_user_exists(user, &useridnr) == -1) { qerrorf("Error: cannot verify existence of user [%s].\n", user); result = -1; goto freeall; } if (useridnr == 0) { qerrorf("Error: user [%s] does not exist.\n", user); result = -1; goto freeall; } } /* Only get a password for those modes which require it. */ switch (mode) { case 'a': case 'c': if (change_flags.newpasswdstdin) { char pw[50]; struct termios oldattr, newattr; /* Get the current terminal state, then disable echo. */ tcgetattr(fileno(stdin), &oldattr); newattr = oldattr; newattr.c_lflag &= ~ECHO; tcsetattr(fileno(stdin), TCSAFLUSH, &newattr); /* Prompt for a password and read until \n or EOF. */ qprintf("Please enter a password (will not echo): "); fflush(stdout); fgets(pw, 50, stdin); /* We don't want the trailing newline. */ len = strlen(pw); if (pw[len-1] == '\n') pw[len-1] = '\0'; /* fgets guarantees a nul terminated string. */ passwd = dm_strdup(pw); /* Restore the previous terminal state (with echo back on). */ tcsetattr(fileno(stdin), TCSANOW, &oldattr); qprintf("\n"); } /* If no password type was specified, and * the user already exists, get their password type. */ if (!passwdtype && useridnr) passwdtype = auth_getencryption(useridnr); /* Convert the password and password type into a * fully coded format, ready for the database. */ if (mkpassword(user, passwd, passwdtype, passwdfile, &password, &enctype)) { qerrorf("Error: unable to create a password.\n"); result = -1; goto freeall; } } switch (mode) { case 'a': result = do_add(user, password, enctype, maxmail, clientid, &alias_add, &alias_del); break; case 'd': result = do_delete(useridnr, user); break; case 'c': qprintf("Performing changes for user [%s]...\n", user); if (change_flags.newuser) { result |= do_username(useridnr, newuser); } if (change_flags.newpasswd) { result |= do_password(useridnr, password, enctype); } if (change_flags.newclientid) { result |= do_clientid(useridnr, clientid); } if (change_flags.newmaxmail) { result |= do_maxmail(useridnr, maxmail); } result |= do_aliases(useridnr, &alias_add, &alias_del); break; case 'e': result = do_empty(useridnr); break; case 'l': result = do_show(userspec); break; case 'x': result = do_forwards(alias, clientid, &fwds_add, &fwds_del); break; default: result = 1; } /* Here's where we free memory and quit. * Be sure that all of these are NULL safe! */ freeall: if (user) dm_free(user); if (passwd) dm_free(passwd); if (alias) dm_free(alias); if (userspec) dm_free(userspec); if (passwdfile) dm_free(passwdfile); if (newuser) dm_free(newuser); /* Free the lists. */ if (alias_del.start) list_freelist(&alias_del.start); if (alias_add.start) list_freelist(&alias_add.start); if (fwds_del.start) list_freelist(&alias_del.start); if (fwds_add.start) list_freelist(&alias_add.start); db_disconnect(); auth_disconnect(); config_free(); if (result < 0) qerrorf("Command failed.\n"); return result; } int do_add(const char * const user, const char * const password, const char * const enctype, const u64_t maxmail, const u64_t clientid, struct list * const alias_add, struct list * const alias_del) { u64_t useridnr; u64_t mailbox_idnr; int add_user_result, result; if (!is_valid(user)) { qerrorf("Error: invalid characters in username [%s]\n", user); return -1; } qprintf("Adding user %s with password type %s," "%llu bytes mailbox limit and clientid %llu... ", user, enctype, maxmail, clientid); switch (auth_user_exists(user, &useridnr)) { case -1: /* Database failure */ qerrorf("Failed\n\nCheck logs for details\n\n"); return -1; default: if (useridnr != 0) { qprintf("Failed: user exists [%llu]\n", useridnr); return -1; } else { /* If useridnr is 0, create the user */ add_user_result = auth_adduser(user, password, enctype, clientid, maxmail, &useridnr); } break; } qprintf("Ok, user added id [%llu]\n", useridnr); /* Add an INBOX for the user. */ qprintf("Adding INBOX for new user\n"); switch(db_createmailbox("INBOX", useridnr, &mailbox_idnr)) { case -1: qprintf("Failed.. User is added but we failed to add " "the mailbox INBOX for this user\n"); result = -1; break; case 0: default: qprintf("Ok. added\n"); result = 0; break; } if(do_aliases(useridnr, alias_add, alias_del) < 0) result = -1; return result; } /* Change of username */ int do_username(const u64_t useridnr, const char * const newuser) { int result = 0; if (newuser && is_valid(newuser)) { if (auth_change_username(useridnr, newuser) != 0) { qerrorf("Error: could not change username.\n"); result = -1; } } else { qerrorf("Error: new username contains invalid characters.\n"); result = -1; } return result; } /* Change of password */ int do_password(const u64_t useridnr, const char * const password, const char * const enctype) { int result = 0; result = auth_change_password(useridnr, password, enctype); if (result != 0) { qerrorf("Error: could not change password.\n"); } return result; } /* These are the available password types. */ typedef enum { PLAINTEXT = 0, PLAINTEXT_RAW, CRYPT, CRYPT_RAW, MD5_HASH, MD5_HASH_RAW, MD5_DIGEST, MD5_DIGEST_RAW, SHADOW, PWTYPE_NULL } pwtype_t; /* These are the easy text names. */ static const char * const pwtypes[] = { "plaintext", "plaintext-raw", "crypt", "crypt-raw", "md5", "md5-raw", "md5sum", "md5sum-raw", "md5-hash", "md5-hash-raw", "md5-digest", "md5-digest-raw", "shadow", "", NULL }; /* These must correspond to the easy text names. */ static const pwtype_t pwtypecodes[] = { PLAINTEXT, PLAINTEXT_RAW, CRYPT, CRYPT_RAW, MD5_HASH, MD5_HASH_RAW, MD5_DIGEST, MD5_DIGEST_RAW, MD5_HASH, MD5_HASH_RAW, MD5_DIGEST, MD5_DIGEST_RAW, SHADOW, PLAINTEXT, PWTYPE_NULL }; int mkpassword(const char * const user, const char * const passwd, const char * const passwdtype, const char * const passwdfile, char ** password, char ** enctype) { pwtype_t pwtype; int pwindex = 0; int result = 0; char *entry = NULL; char pw[50]; memset(pw, 0, 50); /* Only search if there's a string to compare. */ if (passwdtype) /* Find a matching pwtype. */ for (pwindex = 0; pwtypecodes[pwindex] < PWTYPE_NULL; pwindex++) if (strcasecmp(passwdtype, pwtypes[pwindex]) == 0) break; /* If no search took place, pwindex is 0, PLAINTEXT. */ pwtype = pwtypecodes[pwindex]; switch (pwtype) { case PLAINTEXT: case PLAINTEXT_RAW: null_strncpy(pw, passwd, 49); *enctype = ""; break; case CRYPT: strcat(pw, null_crypt(passwd, cget_salt())); *enctype = "crypt"; break; case CRYPT_RAW: null_strncpy(pw, passwd, 49); *enctype = "crypt"; break; case MD5_HASH: sprintf(pw, "%s%s%s", "$1$", cget_salt(), "$"); null_strncpy(pw, null_crypt(passwd, pw), 49); *enctype = "md5"; break; case MD5_HASH_RAW: null_strncpy(pw, passwd, 49); *enctype = "md5"; break; case MD5_DIGEST: null_strncpy(pw, makemd5(passwd), 49); *enctype = "md5sum"; break; case MD5_DIGEST_RAW: null_strncpy(pw, passwd, 49); *enctype = "md5sum"; break; case SHADOW: entry = bgetpwent(passwdfile, user); if (!entry) { qerrorf("Error: cannot read file [%s], " "please make sure that you have " "permission to read this file.\n", passwdfile); result = -1; break; } null_strncpy(pw, entry, 49); if (strcmp(pw, "") == 0) { qerrorf("Error: password for user [%s] not found in file [%s].\n", user, passwdfile); result = -1; break; } /* Safe because we know pw is 50 long. */ if (strncmp(pw, "$1$", 3) == 0) { *enctype = "md5"; } else { *enctype = "crypt"; } break; default: qerrorf("Error: password type not supported [%s].\n", passwdtype); result = -1; break; } /* Pass this out of the function. */ *password = dm_strdup(pw); return result; } /* Change of client id. */ int do_clientid(u64_t useridnr, u64_t clientid) { int result = 0; if (auth_change_clientid(useridnr, clientid) != 0) { qprintf("\nWarning: could not change client id "); result = -1; } return result; } /* Change of quota / max mail. */ int do_maxmail(u64_t useridnr, u64_t maxmail) { int result = 0; if (auth_change_mailboxsize(useridnr, maxmail) != 0) { qerrorf("Error: could not change max mail size.\n"); result = -1; } return result; } int do_forwards(const char * const alias, const u64_t clientid, struct list * const fwds_add, struct list * const fwds_del) { int result = 0; char *forward; struct element *tmp; /* Delete aliases for the user. */ if (fwds_del) { tmp = list_getstart(fwds_del); while (tmp) { forward = (char *)tmp->data; qprintf("[%s]\n", forward); if (db_removealias_ext(alias, forward) < 0) { qerrorf("Error: could not remove forward [%s] \n", forward); result = -1; } tmp = tmp->nextnode; } } /* Add aliases for the user. */ if (fwds_add) { tmp = list_getstart(fwds_add); while (tmp) { forward = (char *)tmp->data; qprintf("[%s]\n", forward); if (db_addalias_ext(alias, forward, clientid) < 0) { qerrorf("Error: could not add forward [%s]\n", alias); result = -1; } tmp = tmp->nextnode; } } /* qprintf("Adding alias [%s] --> [%s]...", alias, forward); switch ((result = db_addalias_ext(alias, forward, 0))) { case -1: qerrorf("Error: cannot add forwarding address.\n"); break; case 0: qprintf("Ok. Forwarding address added.\n"); break; case 1: qprintf("Already exists. no extra alias added\n"); result = -1; / * return error * / break; } */ qprintf("Done\n"); return result; } int do_aliases(const u64_t useridnr, struct list * const alias_add, struct list * const alias_del) { int result = 0; u64_t clientid; auth_getclientid(useridnr, &clientid); /* Delete aliases for the user. */ if (alias_del) { char *alias; struct element *tmp; tmp = list_getstart(alias_del); while (tmp) { alias = (char *)tmp->data; qprintf("[%s]\n", alias); if (db_removealias(useridnr, alias) < 0) { qerrorf("Error: could not remove alias [%s] \n", alias); result = -1; } tmp = tmp->nextnode; } } /* Add aliases for the user. */ if (alias_add) { char *alias; struct element *tmp; tmp = list_getstart(alias_add); while (tmp) { alias = (char *)tmp->data; qprintf("[%s]\n", alias); if (db_addalias (useridnr, alias, clientid) < 0) { qerrorf("Error: could not add alias [%s]\n", alias); result = -1; } tmp = tmp->nextnode; } } qprintf("Done\n"); return result; } int do_delete(const u64_t useridnr, const char * const name) { int result; struct list aliases; qprintf("Deleting aliases for user [%s]...\n", name); db_get_user_aliases(useridnr, &aliases); do_aliases(useridnr, NULL, &aliases); qprintf("Deleting user [%s]...\n", name); result = auth_delete_user(name); if (result < 0) { qprintf("Failed. Please check the log\n"); return -1; } qprintf("Done\n"); return 0; } int do_show(const char * const name) { u64_t useridnr, cid, quotum, quotumused; struct list userlist; struct element *tmp; char *deliver_to; if (!name) { /* show all users */ qprintf("Existing users:\n"); auth_get_known_users(&userlist); tmp = list_getstart(&userlist); while (tmp) { qprintf("[%s]\n", (char *) tmp->data); tmp = tmp->nextnode; } if (userlist.start) list_freelist(&userlist.start); } else { qprintf("Info for user [%s]", name); if (auth_user_exists(name, &useridnr) == -1) { qerrorf("Error: cannot verify existence of user [%s].\n", name); return -1; } if (useridnr == 0) { /* 'name' is not a user, try it as an alias */ qprintf ("..is not a user, trying as an alias"); deliver_to = db_get_deliver_from_alias(name); if (!deliver_to) { qerrorf("Error: cannot verify existence of alias [%s].\n", name); return -1; } if (deliver_to[0] == '\0') { qprintf("..is not an alias.\n"); return -1; } useridnr = strtoul(deliver_to, NULL, 10); if (useridnr == 0) { qprintf ("\n[%s] is an alias for [%s]\n", name, deliver_to); dm_free(deliver_to); return 0; } dm_free(deliver_to); qprintf("\nFound user for alias [%s]:\n\n", name); } auth_getclientid(useridnr, &cid); auth_getmaxmailsize(useridnr, "um); db_get_quotum_used(useridnr, "umused); qprintf("\n"); qprintf("User ID : %llu\n", useridnr); qprintf("Username : %s\n", auth_get_userid(useridnr)); qprintf("Client ID : %llu\n", cid); qprintf("Max. mailboxsize: %.02f MB\n", (double) quotum / (1024.0 * 1024.0)); qprintf("Quotum used : %.02f MB (%.01f%%)\n", (double) quotumused / (1024.0 * 1024.0), (100.0 * quotumused) / (double) quotum); qprintf("\n"); qprintf("Aliases:\n"); db_get_user_aliases(useridnr, &userlist); tmp = list_getstart(&userlist); while (tmp) { qprintf("%s\n", (char *) tmp->data); tmp = tmp->nextnode; } qprintf("\n"); if (userlist.start) list_freelist(&userlist.start); } return 0; } /* * empties the mailbox associated with user 'name' */ int do_empty(u64_t useridnr) { int result; qprintf("Emptying mailbox..."); fflush(stdout); result = db_empty_mailbox(useridnr); if (result != 0) qerrorf("Error. Please check the log.\n"); else qprintf("Ok.\n"); return result; } int is_valid(const char *str) { int i; for (i = 0; str[i]; i++) if (strchr(ValidChars, str[i]) == NULL) return 0; return 1; } /*eddy This two function was base from "cpu" by Blake Matheny bgetpwent : get hash password from /etc/shadow cget_salt : generate salt value for crypt */ char *bgetpwent(const char *filename, const char *name) { FILE *passfile = NULL; char pass_char[512]; int pass_size = 511; char *pw = NULL; char *user = NULL; if ((passfile = fopen(filename, "r")) == NULL) return NULL; while (fgets(pass_char, pass_size, passfile) != NULL) { char *m = pass_char; int num_tok = 0; char *toks; while (m != NULL && *m != 0) { toks = getToken(&m, ":"); if (num_tok == 0) user = toks; else if (num_tok == 1) /*result->pw_passwd = toks; */ pw = toks; else break; num_tok++; } if (strcmp(user, name) == 0) return pw; } return ""; } char *cget_salt() { unsigned long seed[2]; const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; int i; seed[0] = time(NULL); seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); for (i = 0; i < 8; i++) csalt[i] = seedchars[(seed[i / 5] >> (i % 5) * 6) & 0x3f]; return csalt; } /* This function was base on function of "cpu" by Blake Matheny getToken : break down username and password from a file */ char *getToken(char **str, const char *delims) { char *token; if (*str == NULL) { /* No more tokens */ return NULL; } token = *str; while (**str != '\0') { if (strchr(delims, **str) != NULL) { **str = '\0'; (*str)++; return token; } (*str)++; } /* There is no other token */ *str = NULL; return token; } u64_t strtomaxmail(const char * const str) { u64_t maxmail; char *endptr = NULL; maxmail = strtoull(str, &endptr, 10); switch (*endptr) { case 'g': case 'G': maxmail *= (1024 * 1024 * 1024); break; case 'm': case 'M': maxmail *= (1024 * 1024); break; case 'k': case 'K': maxmail *= 1024; break; } return maxmail; }