struct userdb_template * userdb_template_build(pool_t pool, const char *userdb_name, const char *args) { struct userdb_template *tmpl; const char *const *tmp, *key, *value, *nonull_value; uid_t uid; gid_t gid; tmpl = p_new(pool, struct userdb_template, 1); tmp = t_strsplit_spaces(args, " "); p_array_init(&tmpl->args, pool, str_array_length(tmp)); for (; *tmp != NULL; tmp++) { value = strchr(*tmp, '='); if (value == NULL) key = *tmp; else key = t_strdup_until(*tmp, value++); nonull_value = value == NULL ? "" : value; if (strcasecmp(key, "uid") == 0) { uid = userdb_parse_uid(NULL, nonull_value); if (uid == (uid_t)-1) { i_fatal("%s userdb: Invalid uid: %s", userdb_name, nonull_value); } value = dec2str(uid); } else if (strcasecmp(key, "gid") == 0) { gid = userdb_parse_gid(NULL, nonull_value); if (gid == (gid_t)-1) { i_fatal("%s userdb: Invalid gid: %s", userdb_name, nonull_value); } value = dec2str(gid); } else if (*key == '\0') { i_fatal("%s userdb: Empty key (=%s)", userdb_name, nonull_value); } key = p_strdup(pool, key); value = p_strdup(pool, value); array_append(&tmpl->args, &key, 1); array_append(&tmpl->args, &value, 1); } return tmpl; }
passwd_file_add(struct passwd_file *pw, const char *username, const char *pass, const char *const *args) { /* args = uid, gid, user info, home dir, shell, extra_fields */ struct passwd_user *pu; const char *extra_fields = NULL; char *user; size_t len; if (hash_table_lookup(pw->users, username) != NULL) { i_error("passwd-file %s: User %s exists more than once", pw->path, username); return; } pu = p_new(pw->pool, struct passwd_user, 1); user = p_strdup(pw->pool, username); len = pass == NULL ? 0 : strlen(pass); if (len > 4 && pass[0] != '{' && pass[0] != '$' && pass[len-1] == ']' && pass[len-4] == '[') { /* password[type] - we're being libpam-pwdfile compatible here. it uses 13 = DES and 34 = MD5. For backwards comaptibility with ourself, we have also 56 = Digest-MD5. */ int num = (pass[len-3] - '0') * 10 + (pass[len-2] - '0'); pass = t_strndup(pass, len-4); if (num == 34) { pu->password = p_strconcat(pw->pool, "{PLAIN-MD5}", pass, NULL); } else if (num == 56) { pu->password = p_strconcat(pw->pool, "{DIGEST-MD5}", pass, NULL); if (strlen(pu->password) != 32 + 12) { i_error("passwd-file %s: User %s " "has invalid password", pw->path, username); return; } } else { pu->password = p_strconcat(pw->pool, "{CRYPT}", pass, NULL); } } else { pu->password = p_strdup(pw->pool, pass); } pu->uid = (uid_t)-1; pu->gid = (gid_t)-1; if (*args == NULL) ; else if (!pw->db->userdb || **args == '\0') { args++; } else { pu->uid = userdb_parse_uid(NULL, *args); if (pu->uid == 0 || pu->uid == (uid_t)-1) { i_error("passwd-file %s: User %s has invalid UID '%s'", pw->path, username, *args); return; } args++; } if (*args == NULL) { if (pw->db->userdb_warn_missing) { i_error("passwd-file %s: User %s is missing " "userdb info", pw->path, username); } /* don't allow userdb lookups */ pu->uid = 0; pu->gid = 0; } else if (!pw->db->userdb || **args == '\0') args++; else { pu->gid = userdb_parse_gid(NULL, *args); if (pu->gid == 0 || pu->gid == (gid_t)-1) { i_error("passwd-file %s: User %s has invalid GID '%s'", pw->path, username, *args); return; } args++; } /* user info */ if (*args != NULL) args++; /* home */ if (*args != NULL) { if (pw->db->userdb) pu->home = p_strdup_empty(pw->pool, *args); args++; } /* shell */ if (*args != NULL) args++; if (*args != NULL && **args == '\0') { /* old format, this field is empty and next field may contain MAIL */ args++; if (*args != NULL && **args != '\0' && pw->db->userdb) { extra_fields = t_strconcat("userdb_mail=", t_strarray_join(args, ":"), NULL); } } else if (*args != NULL) { /* new format, contains a space separated list of extra fields */ extra_fields = t_strarray_join(args, ":"); } if (extra_fields != NULL) { pu->extra_fields = p_strsplit_spaces(pw->pool, extra_fields, " "); } hash_table_insert(pw->users, user, pu); }