aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sftp_server/config.c52
-rw-r--r--sftp_server/main.c84
-rw-r--r--sftp_server/server.h4
-rw-r--r--sftp_server/sftp.conf1
4 files changed, 136 insertions, 5 deletions
diff --git a/sftp_server/config.c b/sftp_server/config.c
index be69d077..3dc2bc6f 100644
--- a/sftp_server/config.c
+++ b/sftp_server/config.c
@@ -136,6 +136,8 @@ int group_callback(const char *shortvar, const char *var, const char *arguments,
if(!strcasecmp(shortvar,"chroot")){
current_group->chroot=strdup(value);
}
+ if(!strcasecmp(shortvar,"nopassword"))
+ current_group->nopassword=1;
}
return LC_CBRET_OKAY;
}
@@ -278,6 +280,7 @@ int parse_config(char *file){
r=lc_register_callback("group.uid",0,LC_VAR_UNKNOWN,group_callback,NULL);
r=lc_register_callback("group.chroot",0,LC_VAR_UNKNOWN,group_callback,NULL);
r=lc_register_callback("group.group",0,LC_VAR_UNKNOWN,group_callback,NULL);
+ r=lc_register_callback("group.nopassword",0,LC_VAR_NONE,group_callback,NULL);
// lc_register_var("dir", LC_VAR_SECTION, NULL, 0);
r=lc_register_callback("dir",0,LC_VAR_NONE,dir_callback,NULL);
r=lc_register_callback("dir.list",0,LC_VAR_UNKNOWN,dir_callback,NULL);
@@ -291,3 +294,52 @@ int parse_config(char *file){
list_config();
return 0;
}
+
+list *find_groups(char *user){
+ return list_find(users,user);
+}
+
+char *user_chroot(char *user){
+ char *c_grp;
+ list *group=find_groups(user);
+ struct group *grp;
+ while(group){
+ c_grp=group->key;
+ grp=list_find(groups,c_grp);
+ if(grp->chroot)
+ return grp->chroot;
+ group=group->next;
+ }
+ return NULL;
+}
+
+char *user_uid(char *user){
+ char *c_grp;
+ list *group=find_groups(user);
+ struct group *grp;
+ while(group){
+ c_grp=group->key;
+ grp=list_find(groups,c_grp);
+ if(grp->uid)
+ return grp->uid;
+ group=group->next;
+ }
+ return NULL;
+}
+
+/* 0 if it's not specified. 1 if the user doesn't need a password */
+int user_nopassword(char *user){
+ char *c_grp;
+ list *group=find_groups(user);
+ struct group *grp;
+ if(!group)
+ return 0; //user doesn't exist
+ while(group){
+ c_grp=group->key;
+ grp=list_find(groups,c_grp);
+ if(grp->nopassword)
+ return 1;
+ group=group->next;
+ }
+ return 0;
+}
diff --git a/sftp_server/main.c b/sftp_server/main.c
index 7b276d2e..949b9979 100644
--- a/sftp_server/main.c
+++ b/sftp_server/main.c
@@ -35,6 +35,7 @@ MA 02111-1307, USA. */
#include <stdio.h>
#include <signal.h>
#include <security/pam_appl.h>
+#include <pwd.h>
#include "server.h"
@@ -81,7 +82,59 @@ int password_conv(int num_msg, const struct pam_message **msg,
return PAM_SUCCESS;
}
-
+/* postauth_conf returns -1 on error, else 0 */
+int postauth_conf(char *user){
+ /* first, find a chroot if any */
+ char *root,*ptr;
+ char *char_uid;
+ char buffer[256];
+ int uid;
+ struct passwd *pw=getpwnam(user);
+ root=user_chroot(user);
+ if(root){
+ if((ptr=strstr(root,"$HOME"))){
+ if(!pw)
+ return -1; // this user has no user directory
+ *ptr=0;
+ snprintf(buffer,sizeof(buffer),"%s%s/%s",
+ root,pw->pw_dir,ptr+strlen("$HOME"));
+ }
+ else
+ snprintf(buffer,sizeof(buffer),"%s",root);
+ }
+ /* we don't chroot right now because we still need getpwnam() */
+ char_uid=user_uid(user);
+ if(!char_uid){
+ if(!pw)
+ return -1; // user doesn't exist !
+ char_uid=user;
+ }
+ uid=atoi(char_uid);
+ if(uid==0 && char_uid[0]!=0){
+ pw=getpwnam(char_uid);
+ if(!pw)
+ return -1;
+ uid=pw->pw_uid;
+ }
+ if(root && chroot(buffer)){
+ return -1; // cannot chroot
+ }
+ if(root){
+ chdir("/");
+ } else {
+ if(pw)
+ chdir(pw->pw_dir);
+ else
+ chdir("/");
+ }
+ if(setuid(uid)){
+ return -1; // cannot setuid
+ }
+ return 0;
+}
+
+
+
struct pam_conv pam_conv ={ password_conv, NULL };
/* returns 1 if authenticated, 0 if failed,
-1 if you must leave */
@@ -101,6 +154,8 @@ int auth_password(char *user, char *password){
memset(password,0,strlen(password));
if(ret==PAM_SUCCESS){
pam_end(pamh,PAM_SUCCESS);
+ if(postauth_conf(user))
+ return -1;
return 1;
} else {
pam_end(pamh,PAM_AUTH_ERR);
@@ -469,13 +524,32 @@ int do_auth(SSH_SESSION *session){
ssh_say(1,"Auth refused\n");
break;
}
- if(auth==1)
+ if(auth==1){
break;
+ } else {
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ break;
// not authenticated, send default message
case SSH_AUTH_NONE:
- //ssh_message_auth_reply_success(message,0);
- //auth=1;
- //break;
+ if(user_nopassword(ssh_message_auth_user(message))){
+ if(postauth_conf(ssh_message_auth_user(message))==0){
+ ssh_message_auth_reply_success(message,0);
+ auth=1;
+ ssh_say(1,"Authentication success for %s(no password)\n",
+ ssh_message_auth_user(message));
+ break;
+ } else {
+ ssh_say(1,"Post-auth failed\n");
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ } else {
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ break;
default:
ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
ssh_message_reply_default(message);
diff --git a/sftp_server/server.h b/sftp_server/server.h
index 866eb70c..1457e81f 100644
--- a/sftp_server/server.h
+++ b/sftp_server/server.h
@@ -1,6 +1,9 @@
/* server.h */
/* headers for the sftp server project */
int parse_config(char *file);
+char *user_chroot(char *user);
+char *user_uid(char *user);
+int user_nopassword(char *user);
typedef struct list_struct {
struct list_struct *next;
@@ -17,6 +20,7 @@ struct group {
char *chroot;
char *uid;
char *gid;
+ int nopassword;
};
struct dir {
diff --git a/sftp_server/sftp.conf b/sftp_server/sftp.conf
index f17aae83..842c91c9 100644
--- a/sftp_server/sftp.conf
+++ b/sftp_server/sftp.conf
@@ -8,6 +8,7 @@ Hostkeydsa /etc/ssh/ssh_host_dsa_key
<group anonymous>
user ftp, anonymous, anon
uid ftp
+ nopassword
chroot /home/ftp
</group>
<group users>