pam_winbind: re-add mkhomedir option.
authorGünther Deschner <gd@samba.org>
Thu, 14 Aug 2008 12:39:52 +0000 (14:39 +0200)
committerGünther Deschner <gd@samba.org>
Fri, 10 Oct 2008 13:42:56 +0000 (15:42 +0200)
Guenther

examples/pam_winbind/pam_winbind.conf
source3/nsswitch/pam_winbind.c
source3/nsswitch/pam_winbind.h

index a9e02a833a526f647ce7838a44e08a3ef5bd2dad..dd0b112f30424e8df3e956d9f9d6defd5a9435c2 100644 (file)
@@ -33,3 +33,6 @@
 
 # omit pam conversations
 ;silent = no
+
+# create homedirectory on the fly
+;mkhomedir = no
index a9d6aa650ad4154a70df416bf85507d9d7d6dec1..8d8868d0ef2d62b8a942a399c9a26adc97208f24 100644 (file)
@@ -437,6 +437,10 @@ static int _pam_parse(const pam_handle_t *pamh,
                ctrl |= WINBIND_WARN_PWD_EXPIRE;
        }
 
+       if (iniparser_getboolean(d, "global:mkhomedir", false)) {
+               ctrl |= WINBIND_MKHOMEDIR;
+       }
+
 config_from_pam:
        /* step through arguments */
        for (i=argc,v=argv; i-- > 0; ++v) {
@@ -469,6 +473,8 @@ config_from_pam:
                        ctrl |= WINBIND_KRB5_CCACHE_TYPE;
                else if (!strcasecmp(*v, "cached_login"))
                        ctrl |= WINBIND_CACHED_LOGIN;
+               else if (!strcasecmp(*v, "mkhomedir"))
+                       ctrl |= WINBIND_MKHOMEDIR;
                else {
                        __pam_log(pamh, ctrl, LOG_ERR,
                                 "pam_parse: unknown option: %s", *v);
@@ -1378,6 +1384,127 @@ static char *_pam_compose_pwd_restriction_string(struct pwb_context *ctx,
        return NULL;
 }
 
+static int _pam_create_homedir(struct pwb_context *ctx,
+                              const char *dirname,
+                              mode_t mode)
+{
+       struct stat sbuf;
+
+       if (stat(dirname, &sbuf) == 0) {
+               return PAM_SUCCESS;
+       }
+
+       if (mkdir(dirname, mode) != 0) {
+
+               _make_remark_format(ctx, PAM_TEXT_INFO,
+                                   "Creating directory: %s failed: %s",
+                                   dirname, strerror(errno));
+               _pam_log(ctx, LOG_ERR, "could not create dir: %s (%s)",
+                dirname, strerror(errno));
+                return PAM_PERM_DENIED;
+       }
+
+       return PAM_SUCCESS;
+}
+
+static int _pam_chown_homedir(struct pwb_context *ctx,
+                             const char *dirname,
+                             uid_t uid,
+                             gid_t gid)
+{
+       if (chown(dirname, uid, gid) != 0) {
+               _pam_log(ctx, LOG_ERR, "failed to chown user homedir: %s (%s)",
+                        dirname, strerror(errno));
+               return PAM_PERM_DENIED;
+       }
+
+       return PAM_SUCCESS;
+}
+
+static int _pam_mkhomedir(struct pwb_context *ctx)
+{
+       struct passwd *pwd = NULL;
+       char *token = NULL;
+       char *create_dir = NULL;
+       char *user_dir = NULL;
+       int ret;
+       const char *username;
+       mode_t mode = 0700;
+       char *safe_ptr = NULL;
+       char *p = NULL;
+
+       /* Get the username */
+       ret = pam_get_user(ctx->pamh, &username, NULL);
+       if ((ret != PAM_SUCCESS) || (!username)) {
+               _pam_log_debug(ctx, LOG_DEBUG, "can not get the username");
+               return PAM_SERVICE_ERR;
+       }
+
+       pwd = getpwnam(username);
+       if (pwd == NULL) {
+               _pam_log_debug(ctx, LOG_DEBUG, "can not get the username");
+               return PAM_USER_UNKNOWN;
+       }
+       _pam_log_debug(ctx, LOG_DEBUG, "homedir is: %s", pwd->pw_dir);
+
+       ret = _pam_create_homedir(ctx, pwd->pw_dir, 0700);
+       if (ret == PAM_SUCCESS) {
+               ret = _pam_chown_homedir(ctx, pwd->pw_dir,
+                                        pwd->pw_uid,
+                                        pwd->pw_gid);
+       }
+
+       if (ret == PAM_SUCCESS) {
+               return ret;
+       }
+
+       /* maybe we need to create parent dirs */
+       create_dir = talloc_strdup(ctx, "/");
+       if (!create_dir) {
+               return PAM_BUF_ERR;
+       }
+
+       /* find final directory */
+       user_dir = strrchr(pwd->pw_dir, '/');
+       if (!user_dir) {
+               return PAM_BUF_ERR;
+       }
+       user_dir++;
+
+       _pam_log(ctx, LOG_DEBUG, "final directory: %s", user_dir);
+
+       p = pwd->pw_dir;
+
+       while ((token = strtok_r(p, "/", &safe_ptr)) != NULL) {
+
+               mode = 0755;
+
+               p = NULL;
+
+               _pam_log_debug(ctx, LOG_DEBUG, "token is %s", token);
+
+               create_dir = talloc_asprintf_append(create_dir, "%s/", token);
+               if (!create_dir) {
+                       return PAM_BUF_ERR;
+               }
+               _pam_log_debug(ctx, LOG_DEBUG, "current_dir is %s", create_dir);
+
+               if (strcmp(token, user_dir) == 0) {
+                       _pam_log_debug(ctx, LOG_DEBUG, "assuming last directory: %s", token);
+                       mode = 0700;
+               }
+
+               ret = _pam_create_homedir(ctx, create_dir, mode);
+               if (ret) {
+                       return ret;
+               }
+       }
+
+       return _pam_chown_homedir(ctx, create_dir,
+                                 pwd->pw_uid,
+                                 pwd->pw_gid);
+}
+
 /* talk to winbindd */
 static int winbind_auth_request(struct pwb_context *ctx,
                                const char *user,
@@ -2470,7 +2597,7 @@ PAM_EXTERN
 int pam_sm_open_session(pam_handle_t *pamh, int flags,
                        int argc, const char **argv)
 {
-       int ret = PAM_SYSTEM_ERR;
+       int ret = PAM_SUCCESS;
        struct pwb_context *ctx = NULL;
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
@@ -2480,8 +2607,10 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
 
        _PAM_LOG_FUNCTION_ENTER("pam_sm_open_session", ctx);
 
-       ret = PAM_SUCCESS;
-
+       if (ctx->ctrl & WINBIND_MKHOMEDIR) {
+               /* check and create homedir */
+               ret = _pam_mkhomedir(ctx);
+       }
  out:
        _PAM_LOG_FUNCTION_LEAVE("pam_sm_open_session", ctx, ret);
 
index e7c869c843bfe49cd3969362139cbb12bbc7543a..cb6f450ccb7ded1c3c6fe202de08cda34288cebb 100644 (file)
@@ -99,6 +99,7 @@ do {                             \
 #define WINBIND_SILENT                 0x00000800
 #define WINBIND_DEBUG_STATE            0x00001000
 #define WINBIND_WARN_PWD_EXPIRE                0x00002000
+#define WINBIND_MKHOMEDIR              0x00004000
 
 /*
  * here is the string to inform the user that the new passwords they