X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fuser_ops.c;h=82f693a4ea0a83a1395818ea4688b248d24fd66b;hb=5f2b9b3de88c662fa886ee3fc96a68fd5e52545f;hp=e35953debce23c49e0aa6316c27efe408e96a314;hpb=6b7ec622dd2a18715d3c0f353d23ade3f463f3f3;p=citadel.git diff --git a/citadel/user_ops.c b/citadel/user_ops.c index e35953deb..82f693a4e 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -12,10 +12,12 @@ * GNU General Public License for more details. */ +#include +#include #include "sysdep.h" #include +#include #include - #include "control.h" #include "support.h" #include "citserver.h" @@ -31,14 +33,14 @@ int chkpwd_read_pipe[2]; /* - * CtdlGetUser() - retrieve named user into supplied buffer. - * returns 0 on success + * CtdlGetUser() retrieve named user into supplied buffer. + * returns 0 on success */ -int CtdlGetUserLen(struct ctdluser *usbuf, const char *name, long len) +int CtdlGetUser(struct ctdluser *usbuf, char *name) { - char usernamekey[USERNAME_SIZE]; struct cdbdata *cdbus; + long len = cutuserkey(name); if (usbuf != NULL) { memset(usbuf, 0, sizeof(struct ctdluser)); @@ -51,28 +53,20 @@ int CtdlGetUserLen(struct ctdluser *usbuf, const char *name, long len) return(1); } if (usbuf != NULL) { - memcpy(usbuf, cdbus->ptr, - ((cdbus->len > sizeof(struct ctdluser)) ? - sizeof(struct ctdluser) : cdbus->len)); + memcpy(usbuf, cdbus->ptr, ((cdbus->len > sizeof(struct ctdluser)) ? sizeof(struct ctdluser) : cdbus->len)); } cdb_free(cdbus); - return (0); } -int CtdlGetUser(struct ctdluser *usbuf, char *name) -{ - return CtdlGetUserLen(usbuf, name, cutuserkey(name)); -} - int CtdlLockGetCurrentUser(void) { CitContext *CCC = CC; - - return CtdlGetUserLen(&CCC->user, CCC->curr_user, cutuserkey(CCC->curr_user)); + return CtdlGetUser(&CCC->user, CCC->curr_user); } + /* * CtdlGetUserLock() - same as getuser() but locks the record */ @@ -95,17 +89,12 @@ void CtdlPutUser(struct ctdluser *usbuf) { char usernamekey[USERNAME_SIZE]; - makeuserkey(usernamekey, - usbuf->fullname, - cutuserkey(usbuf->fullname)); - + makeuserkey(usernamekey, usbuf->fullname, cutuserkey(usbuf->fullname)); usbuf->version = REV_LEVEL; - cdb_store(CDB_USERS, - usernamekey, strlen(usernamekey), - usbuf, sizeof(struct ctdluser)); - + cdb_store(CDB_USERS, usernamekey, strlen(usernamekey), usbuf, sizeof(struct ctdluser)); } + void CtdlPutCurrentUserLock() { CtdlPutUser(&CC->user); @@ -122,7 +111,6 @@ void CtdlPutUserLock(struct ctdluser *usbuf) } - /* * rename_user() - this is tricky because the user's display name is the database key * @@ -164,7 +152,7 @@ int rename_user(char *oldname, char *newname) { syslog(LOG_DEBUG, "user_ops: can not rename user \"Citadel\"."); retcode = RENAMEUSER_NOT_FOUND; } else { - syslog(LOG_DEBUG, "user_ops: renaming <%s> to <%s>\n", oldname, newname); + syslog(LOG_DEBUG, "user_ops: renaming <%s> to <%s>", oldname, newname); cdb_delete(CDB_USERS, oldnamekey, strlen(oldnamekey)); safestrncpy(usbuf.fullname, newname, sizeof usbuf.fullname); CtdlPutUser(&usbuf); @@ -180,7 +168,6 @@ int rename_user(char *oldname, char *newname) { } - /* * Index-generating function used by Ctdl[Get|Set]Relationship */ @@ -231,8 +218,6 @@ void CtdlSetRelationship(visit *newvisit, struct ctdluser *rel_user, struct ctdlroom *rel_room) { - - /* We don't use these in Citadel because they're implicit by the * index, but they must be present if the database is exported. */ @@ -243,6 +228,7 @@ void CtdlSetRelationship(visit *newvisit, put_visit(newvisit); } + /* * Locate a relationship between a user and a room */ @@ -250,7 +236,6 @@ void CtdlGetRelationship(visit *vbuf, struct ctdluser *rel_user, struct ctdlroom *rel_room) { - char IndexBuf[32]; int IndexLen; struct cdbdata *cdbvisit; @@ -319,6 +304,7 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { return(0); } + /* * Convenience function. */ @@ -326,8 +312,7 @@ int CtdlAccessCheck(int required_level) { if (CC->internal_pgm) return(0); if (required_level >= ac_internal) { - cprintf("%d This is not a user-level command.\n", - ERROR + HIGHER_ACCESS_REQUIRED); + cprintf("%d This is not a user-level command.\n", ERROR + HIGHER_ACCESS_REQUIRED); return(-1); } @@ -360,7 +345,6 @@ int CtdlAccessCheck(int required_level) } - /* * Is the user currently logged in an Admin? */ @@ -383,8 +367,7 @@ int is_room_aide(void) return (0); } - if ((CC->user.axlevel >= AxAideU) - || (CC->room.QRroomaide == CC->user.usernum)) { + if ((CC->user.axlevel >= AxAideU) || (CC->room.QRroomaide == CC->user.usernum)) { return (1); } else { return (0); @@ -466,30 +449,32 @@ void rebuild_usersbynumber(void) { /* - * getuserbyuid() - get user by system uid (for PAM mode authentication) - * returns 0 if user was found - * - * WARNING: don't use this function unless you absolutely have to. It does - * a sequential search and therefore is computationally expensive. + * getuserbyuid() Get user by system uid (for PAM mode authentication) + * Returns 0 if user was found + * This now uses an extauth index. */ int getuserbyuid(struct ctdluser *usbuf, uid_t number) { - struct cdbdata *cdbus; + struct cdbdata *cdbextauth; + long usernum = 0; + StrBuf *claimed_id; + + claimed_id = NewStrBuf(); + StrBufPrintf(claimed_id, "uid:%d", number); + cdbextauth = cdb_fetch(CDB_EXTAUTH, ChrPtr(claimed_id), StrLength(claimed_id)); + FreeStrBuf(&claimed_id); + if (cdbextauth == NULL) { + return(-1); + } - cdb_rewind(CDB_USERS); + memcpy(&usernum, cdbextauth->ptr, sizeof(long)); + cdb_free(cdbextauth); - while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) { - memset(usbuf, 0, sizeof(struct ctdluser)); - memcpy(usbuf, cdbus->ptr, - ((cdbus->len > sizeof(struct ctdluser)) ? - sizeof(struct ctdluser) : cdbus->len)); - cdb_free(cdbus); - if (usbuf->uid == number) { - cdb_close_cursor(CDB_USERS); - return (0); - } + if (!CtdlGetUserByNumber(usbuf, usernum)) { + return(0); } - return (-1); + + return(-1); } @@ -502,7 +487,6 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) { char username[SIZ]; int found_user; - long len; syslog(LOG_DEBUG, "user_ops: CtdlLoginExistingUser(%s, %s)", authname, trythisname); @@ -531,7 +515,6 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) /* Continue attempting user validation... */ safestrncpy(username, trythisname, sizeof (username)); striplt(username); - len = cutuserkey(username); if (IsEmptyStr(username)) { return login_not_found; @@ -567,12 +550,11 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) * If not found, make one attempt to create it. */ found_user = getuserbyuid(&CC->user, pd.pw_uid); - syslog(LOG_DEBUG, "user_ops: found it: uid=%ld, gecos=%s here: %d", (long)pd.pw_uid, pd.pw_gecos, found_user); if (found_user != 0) { - len = cutuserkey(username); - create_user(username, len, 0); + create_user(username, CREATE_USER_DO_NOT_BECOME_USER, pd.pw_uid); found_user = getuserbyuid(&CC->user, pd.pw_uid); } + syslog(LOG_DEBUG, "user_ops: found it: uid=%ld, gecos=%s here: %d", (long)pd.pw_uid, pd.pw_gecos, found_user); } @@ -585,14 +567,14 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) char ldap_cn[256]; char ldap_dn[256]; - found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid, 0); + found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid); if (found_user != 0) { return login_not_found; } found_user = getuserbyuid(&CC->user, ldap_uid); if (found_user != 0) { - create_user(username, len, 0); + create_user(ldap_cn, CREATE_USER_DO_NOT_BECOME_USER, ldap_uid); found_user = getuserbyuid(&CC->user, ldap_uid); } @@ -612,9 +594,7 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) /* First, try to log in as if the supplied name is a display name */ found_user = CtdlGetUser(&CC->user, username); - /* If that didn't work, try to log in as if the supplied name - * is an e-mail address - */ + /* If that didn't work, try to log in as if the supplied name * is an e-mail address */ if (found_user != 0) { valid = validate_recipients(username, NULL, 0); if (valid != NULL) { @@ -631,8 +611,7 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) if (((CC->nologin)) && (CC->user.axlevel < AxAideU)) { return login_too_many_users; } else { - safestrncpy(CC->curr_user, CC->user.fullname, - sizeof CC->curr_user); + safestrncpy(CC->curr_user, CC->user.fullname, sizeof CC->curr_user); return login_ok; } } @@ -671,16 +650,40 @@ void do_login(void) } } + /* + * If we are using LDAP authentication, extract the user's email addresses from the directory. + * FIXME make this a site configurable setting + */ + #ifdef HAVE_LDAP + if ((CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP) || (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP_AD)) { + char new_emailaddrs[512]; + if (extract_email_addresses_from_ldap(CCC->ldap_dn, new_emailaddrs) == 0) { + strcpy(CCC->user.emailaddrs, new_emailaddrs); + } + } + #endif + + /* + * No email address for user? Make one up. + */ + if (IsEmptyStr(CCC->user.emailaddrs)) { + sprintf(CCC->user.emailaddrs, "cit%ld@%s", CCC->user.usernum, CtdlGetConfigStr("c_fqdn")); + } + CtdlPutUserLock(&CCC->user); /* - * Populate CCC->cs_inet_email with a default address. This will be - * overwritten with the user's directory address, if one exists, when - * the vCard module's login hook runs. + * Populate cs_inet_email and cs_inet_other_emails with valid email addresses from the user record */ - snprintf(CCC->cs_inet_email, sizeof CCC->cs_inet_email, "%s@%s", - CCC->user.fullname, CtdlGetConfigStr("c_fqdn")); - convert_spaces_to_underscores(CCC->cs_inet_email); + strcpy(CCC->cs_inet_email, CCC->user.emailaddrs); + char *firstsep = strstr(CCC->cs_inet_email, "|"); + if (firstsep) { + strcpy(CCC->cs_inet_other_emails, firstsep+1); + *firstsep = 0; + } + else { + CCC->cs_inet_other_emails[0] = 0; + } /* Create any personal rooms required by the system. * (Technically, MAILROOM should be there already, but just in case...) @@ -768,19 +771,19 @@ static int validpw(uid_t uid, const char *pass) begin_critical_section(S_CHKPWD); rv = write(chkpwd_write_pipe[1], &uid, sizeof(uid_t)); if (rv == -1) { - syslog(LOG_EMERG, "user_ops: communication with chkpwd broken: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: communication with chkpwd broken: %m"); end_critical_section(S_CHKPWD); return 0; } rv = write(chkpwd_write_pipe[1], pass, 256); if (rv == -1) { - syslog(LOG_EMERG, "user_ops: communication with chkpwd broken: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: communication with chkpwd broken: %m"); end_critical_section(S_CHKPWD); return 0; } rv = read(chkpwd_read_pipe[0], buf, 4); if (rv == -1) { - syslog(LOG_EMERG, "user_ops: ommunication with chkpwd broken: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: ommunication with chkpwd broken: %m"); end_critical_section(S_CHKPWD); return 0; } @@ -807,21 +810,21 @@ void start_chkpwd_daemon(void) { syslog(LOG_DEBUG, "user_ops: starting chkpwd daemon for host authentication mode"); if ((stat(file_chkpwd, &filestats)==-1) || (filestats.st_size==0)) { - printf("didn't find chkpwd daemon in %s: %s\n", file_chkpwd, strerror(errno)); + syslog(LOG_ERR, "user_ops: %s: %m", file_chkpwd); abort(); } if (pipe(chkpwd_write_pipe) != 0) { - syslog(LOG_ERR, "user_ops: unable to create pipe for chkpwd daemon: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: unable to create pipe for chkpwd daemon: %m"); abort(); } if (pipe(chkpwd_read_pipe) != 0) { - syslog(LOG_ERR, "user_ops: unable to create pipe for chkpwd daemon: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: unable to create pipe for chkpwd daemon: %m"); abort(); } chkpwd_pid = fork(); if (chkpwd_pid < 0) { - syslog(LOG_ERR, "user_ops: unable to fork chkpwd daemon: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: unable to fork chkpwd daemon: %m"); abort(); } if (chkpwd_pid == 0) { @@ -829,7 +832,7 @@ void start_chkpwd_daemon(void) { dup2(chkpwd_read_pipe[1], 1); for (i=2; i<256; ++i) close(i); execl(file_chkpwd, file_chkpwd, NULL); - syslog(LOG_ERR, "user_ops: unable to exec chkpwd daemon: %s", strerror(errno)); + syslog(LOG_ERR, "user_ops: unable to exec chkpwd daemon: %m"); abort(); exit(errno); } @@ -995,9 +998,9 @@ int purge_user(char pname[]) } -int internal_create_user (const char *username, long len, struct ctdluser *usbuf, uid_t uid) +int internal_create_user(char *username, struct ctdluser *usbuf, uid_t uid) { - if (!CtdlGetUserLen(usbuf, username, len)) { + if (!CtdlGetUser(usbuf, username)) { return (ERROR + ALREADY_EXISTS); } @@ -1022,6 +1025,14 @@ int internal_create_user (const char *username, long len, struct ctdluser *usbuf CtdlPutUser(usbuf); cdb_store(CDB_USERSBYNUMBER, &usbuf->usernum, sizeof(long), usbuf->fullname, strlen(usbuf->fullname)+1); + /* If non-native auth, index by uid */ + if ((usbuf->uid > 0) && (usbuf->uid != NATIVE_AUTH_UID)) { + StrBuf *claimed_id = NewStrBuf(); + StrBufPrintf(claimed_id, "uid:%d", usbuf->uid); + attach_extauth(usbuf, claimed_id); + FreeStrBuf(&claimed_id); + } + return 0; } @@ -1030,66 +1041,23 @@ int internal_create_user (const char *username, long len, struct ctdluser *usbuf * create_user() - back end processing to create a new user * * Set 'newusername' to the desired account name. - * Set 'become_user' to nonzero if this is self-service account creation and we want - * to actually log in as the user we just created, otherwise set it to 0. + * Set 'become_user' to CREATE_USER_BECOME_USER if this is self-service account creation and we want to + * actually log in as the user we just created, otherwise set it to CREATE_USER_DO_NOT_BECOME_USER + * Set 'uid' to some uid_t value to associate the account with an external auth user, or (-1) for native auth */ -int create_user(const char *newusername, long len, int become_user) +int create_user(char *username, int become_user, uid_t uid) { struct ctdluser usbuf; struct ctdlroom qrbuf; - char username[256]; char mailboxname[ROOMNAMELEN]; char buf[SIZ]; int retval; - uid_t uid = (-1); - - safestrncpy(username, newusername, sizeof username); strproc(username); - - - if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) { - - /* host auth mode */ - - struct passwd pd; - struct passwd *tempPwdPtr; - char pwdbuffer[SIZ]; - -#ifdef HAVE_GETPWNAM_R -#ifdef SOLARIS_GETPWUID - tempPwdPtr = getpwnam_r(username, &pd, pwdbuffer, sizeof(pwdbuffer)); -#else // SOLARIS_GETPWUID - getpwnam_r(username, &pd, pwdbuffer, sizeof pwdbuffer, &tempPwdPtr); -#endif // SOLARIS_GETPWUID -#else // HAVE_GETPWNAM_R - tempPwdPtr = NULL; -#endif // HAVE_GETPWNAM_R - if (tempPwdPtr != NULL) { - extract_token(username, pd.pw_gecos, 0, ',', sizeof username); - uid = pd.pw_uid; - if (IsEmptyStr (username)) - { - safestrncpy(username, pd.pw_name, sizeof username); - len = cutuserkey(username); - } - } - else { - return (ERROR + NO_SUCH_USER); - } + if ((retval = internal_create_user(username, &usbuf, uid)) != 0) { + return retval; } -#ifdef HAVE_LDAP - if ((CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP) || (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP_AD)) { - if (CtdlTryUserLDAP(username, NULL, 0, username, sizeof username, &uid, 0) != 0) { - return(ERROR + NO_SUCH_USER); - } - } -#endif /* HAVE_LDAP */ - - if ((retval = internal_create_user(username, len, &usbuf, uid)) != 0) - return retval; - /* * Give the user a private mailbox and a configuration room. * Make the latter an invisible system room. @@ -1111,7 +1079,7 @@ int create_user(const char *newusername, long len, int become_user) * creating a user, instead of doing self-service account creation */ - if (become_user) { + if (become_user == CREATE_USER_BECOME_USER) { /* Now become the user we just created */ memcpy(&CC->user, &usbuf, sizeof(struct ctdluser)); safestrncpy(CC->curr_user, username, sizeof CC->curr_user);