db-passwd-file.c revision b4ed649cad1f149bb8fc058eb2eb44f0278a729b
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen#if defined (USERDB_PASSWD_FILE) || defined(PASSDB_PASSWD_FILE)
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainenpasswd_file_add(struct passwd_file *pw, const char *username,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* args = uid, gid, user info, home dir, shell, extra_fields */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (hash_table_lookup(pw->users, username) != NULL) {
6b265a8a9d1ce3b3a8033445e99c9035d62ffbc7Timo Sirainen i_error("passwd-file %s: User %s exists more than once",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (len > 4 && pass[0] != '{' && pass[0] != '$' &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* password[type] - we're being libpam-pwdfile compatible
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen here. it uses 13 = DES and 34 = MD5. For backwards
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen comaptibility with ourself, we have also 56 = Digest-MD5. */
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen int num = (pass[len-3] - '0') * 10 + (pass[len-2] - '0');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pu->password = p_strconcat(pw->pool, "{PLAIN-MD5}",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pu->password = p_strconcat(pw->pool, "{DIGEST-MD5}",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "has invalid password",
66c0f96d704f09c88dd03b0ee13a3e9711ffe593Timo Sirainen pu->password = p_strconcat(pw->pool, "{CRYPT}",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("passwd-file %s: User %s has invalid UID '%s'",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* don't allow userdb lookups */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("passwd-file %s: User %s has invalid GID '%s'",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* user info */
1330f999b8076b2f8eed2572c667f7482a555c1bTimo Sirainen /* old format, this field is empty and next field may
1330f999b8076b2f8eed2572c667f7482a555c1bTimo Sirainen contain MAIL */
899ebb8ba3fbebaafd3e431943283719ce2b106dTimo Sirainen if (*args != NULL && **args != '\0' && pw->db->userdb) {
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen /* new format, contains a space separated list of
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen extra fields */
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen p_strsplit_spaces(pw->pool, extra_fields, " ");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct passwd_file *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenpasswd_file_new(struct db_passwd_file *db, const char *expanded_path)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int passwd_file_open(struct passwd_file *pw, bool startup,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char **error_r)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen *error_r = eacces_error_get("open", pw->path);
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen *error_r = t_strdup_printf("open(%s) failed: %m",
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen *error_r = t_strdup_printf("fstat(%s) failed: %m",
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen pw->pool = pool_alloconly_create(MEMPOOL_GROWING"passwd_file", 10240);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen hash_table_create(&pw->users, pw->pool, 0, str_hash, strcmp);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen input = i_stream_create_fd(pw->fd, (size_t)-1);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen i_stream_set_return_partial_line(input, TRUE);
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen if (*line == '\0' || *line == ':' || *line == '#')
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen continue; /* no username or comment */
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen const char *const *args = t_strsplit(line, ":");
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen /* at least username+password */
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen passwd_file_add(pw, args[0], args[1], args+2);
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen /* only username */
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen if ((time_secs > PARSE_TIME_STARTUP_WARN_SECS && startup) ||
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen (time_secs > PARSE_TIME_RELOAD_WARN_SECS && !startup)) {
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen i_warning("passwd-file %s: Reading %u users took %u secs",
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen pw->path, hash_table_count(pw->users), time_secs);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen i_debug("passwd-file %s: Read %u users in %u secs",
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen pw->path, hash_table_count(pw->users), time_secs);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainenstatic void passwd_file_close(struct passwd_file *pw)
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen i_error("passwd-file %s: close() failed: %m", pw->path);
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainenstatic void passwd_file_free(struct passwd_file *pw)
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainenstatic int passwd_file_sync(struct auth_request *request,
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen return hash_table_is_created(pw->users) ? 0 : -1;
5e203e846133e28d0e36ca70ef1c30e72a922c14Timo Sirainen /* with variables don't give hard errors, or errors about
5e203e846133e28d0e36ca70ef1c30e72a922c14Timo Sirainen nonexistent files */
5e203e846133e28d0e36ca70ef1c30e72a922c14Timo Sirainen auth_request_log_error(request, AUTH_SUBSYS_DB,
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen auth_request_log_error(request, AUTH_SUBSYS_DB,
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen if (st.st_mtime != pw->stamp || st.st_size != pw->size) {
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen if (passwd_file_open(pw, FALSE, &error) < 0) {
834f2b9f60d93e4c7dfc6992e692f5b7213a1b11Timo Sirainen auth_request_log_error(request, AUTH_SUBSYS_DB,
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainenstatic struct db_passwd_file *db_passwd_file_find(const char *path)
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainen for (f = passwd_files; f != NULL; f = f->next) {
3b1bf68d26c9f2fe4a649f40cf375d52acffc81cTimo Sirainenstatic void db_passwd_file_set_userdb(struct db_passwd_file *db)
3b1bf68d26c9f2fe4a649f40cf375d52acffc81cTimo Sirainen /* warn about missing userdb fields only when there aren't any other
3b1bf68d26c9f2fe4a649f40cf375d52acffc81cTimo Sirainen array_is_created(&global_auth_settings->userdbs) &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_count(&global_auth_settings->userdbs) == 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainendb_passwd_file_init(const char *path, bool userdb, bool debug)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *p;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* just extra escaped % chars. remove them. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen hash_table_create(&db->files, default_pool, 0,
111a7dda02defa4d612468cfc3c40da5240645afTimo Sirainenvoid db_passwd_file_parse(struct db_passwd_file *db)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (db->default_file != NULL && db->default_file->stamp == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* no variables, open the file immediately */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (passwd_file_open(db->default_file, TRUE, &error) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid db_passwd_file_unref(struct db_passwd_file **_db)
66c0f96d704f09c88dd03b0ee13a3e9711ffe593Timo Sirainen for (p = &passwd_files; *p != NULL; p = &(*p)->next) {
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen if (*p == db) {
if (p == NULL)
return path;
const char *username_format,