/********************************************************************/ /* */ /* QSH_SERVER : QSHELL セッション・サーバー */ /* */ /* [ 原典 ] QZSHSH IN IBM INFOMATION CENTER */ /* */ /* [ 記述 ] This program is a server for starting interactive */ /* qsh sessions on remote clients. */ /* This program listens for connections from clients. */ /* When a connection is accepted, it reads the user */ /* name and password of the client. */ /* It then swaps to the specified user profile and spawn */ /* a new process running the qsh shell interpreter that */ /* handle the connection. */ /* */ /* [ パラメータ ] 1. Port number to listen for connection on. */ /* */ /* [ 注記 ] 1.The user name and password are sent as plain text */ /* from the client. */ /* 2.The user profile running this program must have */ /* authority to the QSYGETPH, QSYRLSPH, and */ /* QWTSETP APIs. */ /* 3.You will need to change the value of the NLSPATH */ /* enviroment valuable if your system is using a */ /* diffrent language than 2924. */ /* */ /********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include /* QpOzInitEnv(), putenv */ #include /* QSYGETPH() */ #include /* QSYRLSPH() */ #include /* Qus_EC_t */ #include /* getpwnam() */ #include /* toupper */ #include #include /* Exception and cancel handling */ #include #include #include #include /*************************************************************/ /* 固 定 定 数 */ /*************************************************************/ #define TRUE 0 #define FALSE -1 #define DEFAULT_BUF 4096 #define DEFAULT_PORT 6042 #define NULL_PH "\0\0\0\0\0\0\0\0\0\0\0\0" #define PH_SIZE 12 #define NAME_SIZE 11 #undef PATH_MAX #define PATH_MAX 4096 /*************************************************************/ /* グ ロ ー バ ル 変 数 */ /*************************************************************/ /* For logging errors */ FILE *log_fp; char log_file[] = "/tmp/qsh_server.log"; char log_buffer[DEFAULT_BUF]; /*************************************************************/ /* 内 部 使 用  関  数 */ /*************************************************************/ int strtoupper(char*); int GetString(int, char*, size_t); void LogError(char*, ...); void SendError(int, char*, ...); void ClearHandler(_CNL_Hndlr_Parms_T *); int main(int argc, char *argv[]){ int sfd; /* Server's listening socket */ int cfd; /* Socket connected to client */ int on=1; /* Flag for setsockopt() */ struct sockaddr_in my_addr; /* Address server binds to */ struct sockaddr_in client_addr; /* Address of connected client */ int client_addr_len; /* Length of client's socket address */ unsigned short port; /* Server's TCP port */ char server_ph[PH_SIZE+1] = NULL_PH;/* Server's profile handle */ char client_ph[PH_SIZE+1] = NULL_PH;/* Client's profile handle */ char profile[NAME_SIZE]; /* User profile read from client */ char password[NAME_SIZE]; /* Password read from client */ char sy_profile[NAME_SIZE];/* User profile for i5/OS APIs */ char sy_password[NAME_SIZE]; /* Password for i/OS APIs */ char server_profile[NAME_SIZE] ="*CURRENT "; char no_pwd[NAME_SIZE] = "*NOPWD "; struct passwd *cpw; /* User information for client */ Qus_EC_t error = {sizeof(Qus_EC_t), 0}; /* Error code for APIs */ /* spawn 関数のためのパラメータ */ char qsh_pgm[] = "/QSYS.LIB/QSHELL.LIB/QZSHSH.PGM"; char *args[5]; /* Argment array */ char *envs[10]; /* Enviroment variable array */ int fd_count; /* Number of Descriptors */ int fd_map[3]; /* Map of descriptors */ struct inheritance inherit; /* Inheritance options */ char server_dir[] = "/"; /* Default current working directory */ /*( 環境変数 )*/ char home_var[PATH_MAX+10]; char logname_var[NAME_SIZE+10]; char path_var[] = "PATH=/usr/bin;,:/QOpenSys/usr/bin"; char stdio_var[] = "QIBM_USE_DESCRIPTOR_STDIO=I"; char terminal_type_var[] = "TERMINAL_TYPE=REMOTE"; char nlspath_var[] = "NLSPATH=/QIBM/ProdData/OS400/Shell/MRI2962/%N"; volatile _INTRPT_Hndlr_Parms_T ca; /*************************************************************/ /* Process the input parameters */ /*************************************************************/ /* Use the default port if one is not specified. */ if(argc < 2){ port = DEFAULT_PORT; } else{ port = atoi(argv[1]); } /*************************************************************/ /* Initialize the server enviroment. */ /*************************************************************/ /* Initialize for enviroment variables. */ Qp0zInitEnv(); /* Change to default directory. */ chdir(server_dir); /* Initialize the server's profile handle. */ QSYGETPH(server_profile, no_pwd, server_ph, &error); if(error.Bytes_Available != 0){ LogError("Could not get profile handle for server, " "QSYGETPH() failed with exception %7.%7s\n", error.Exception_Id); exit(1); } /*************************************************************/ /* Set up listening socket. */ /*************************************************************/ /* Create socket. */ if((sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0){ LogError("socket() failed, error = %d\n", errno); exit(1); } #pragma cancel_handler(CleanupHandler, sfd) #pragma exception_handler(Cleanup, ca, _C1_ALL, C2_ALL) /* Allow re-use of this socket address */ if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int)) != 0){ LogError("setsockopt() failed, error = %d\n", errno); exit(1); } /* Bind to a poer */ memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = port; my_addr.sin_addr.s_addr = INADDR_ANY; if(bind(sfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) != 0){ LogError("bind() failed, error = %d\n", errno); close(sfd); exit(1); } /* make this a listen socket */ if(listen(sfd, 10) != 0){ LogError("listen() failed, error = %d\n", errno); close(sfd); exit(1); } /*************************************************************/ /* Accept connection from clients. */ /*************************************************************/ while(1){/*while*/ if((cfd = accept(sfd, NULL, 0)) < 0){ LogError("accept() failed, error = %d\n", errno); close(sfd); exit(1); } printf("QSH_SERVER: accept OK.\n"); /* Read the user profile and pasword from the client. */ /* the client send two null-terminated strings - */ /* the first one is the user profile and the second */ /* one is the password. */ if(GetString(cfd, profile, 11) != TRUE){ printf("QSH_SERVER: profile = [%s].\n", profile); getpeername(cfd, (struct sockaddr *)&client_addr, &client_addr_len); LogError("Could not read profile from client at %s, port %hu\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port); close(cfd); continue; } printf("QSH_SERVER: profile = [%s]\n", profile); if(GetString(cfd, password, 11) != TRUE){ printf("QSH_SERVER: password = [%s].\n", password); getpeername(cfd, (struct sockaddr *)&client_addr, &client_addr_len); LogError("Could not read password from client at %s, port %hu\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port); close(cfd); continue; } printf("QSH_SERVER: password = [%s]\n", password); /* Check for the special values that turns off passowrd checking */ /* in QSYGETPH() */ if((profile[0] == '*') || (password[0] == '*')){ getpeername(cfd, (struct sockaddr *)&client_addr, &client_addr_len); LogError("Invalid password sent from client at %s, port %hu\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port); close(cfd); continue; } /* QSYHETPH() requires tha the profile be exactly te charactors. */ /* left-aligned in the field, and padded with blanks. */ strtoupper(profile); sprintf(sy_profile, "%-10.10s", profile); printf("[%d] sy_profile = [%s]\n", __LINE__, sy_profile); sprintf(sy_password, "%-10.10s", password); printf("[%d] sy_password = [%s]\n", __LINE__, sy_password); /* Get the profile handle for the client's user profile. */ QSYGETPH(sy_profile, sy_password, client_ph, &error, strlen(password), 0); if(error.Bytes_Available != 0){/* ApiErr */ LogError("Could not get profile handle for profile %s.", sy_profile, error.Exception_Id); SendError(cfd, "Could not get profile handle for profile %s\n", sy_profile); close(cfd); continue; }/* ApiErr */ printf("QSYGETPH success !\n"); /* Switch to client's user profile */ QWTSETP(client_ph, &error); if(error.Bytes_Available != 0){ LogError("Could not switch to profile %s." "QWTSETP() failed with exception %7.7s\n", sy_profile, error.Exception_Id); SendError(cfd, "Could not get profile handle for profile %s\n", sy_profile); close(cfd); continue; } printf("QWTSETP success !\n"); /* Get the info for this user profile */ if((cpw = getpwnam(profile)) == NULL){/* CPW 失敗 */ /* Log error */ LogError("Could not retrieve information for profile %s, " "getpwnam() failed with errno=%d\n", profile, errno); SendError(cfd, "Could not get profile handle for profile %s\n", sy_profile); /* Switch back to the server's user profile */ QWTSETP(server_ph, &error); if(error.Bytes_Available != 0){/* ApiErr */ LogError("Could not switch back to server's profile, " "QWTSETP() failed with exception %7.7s\n", error.Exception_Id); break; }/* ApiErr */ /* Release this client's profile handle */ QSYRLSPH(client_ph, NULL); if(error.Bytes_Available != 0){/* ApiErr */ LogError("Could not release client's profile handle, " "QSYRLSPH() failed with exception %7.7s\n", error.Exception_Id); break; }/* ApiErr */ close(cfd); continue; }/* CPW 失敗 */ /* Build the file descriptor map for the child */ fd_count = 3; fd_map[0] = cfd; fd_map[1] = cfd; fd_map[2] = cfd; /* Build the argv array for the child */ args[0] = qsh_pgm; args[1] = "-login"; /* Do login processing */ args[2] = "-s"; /* Take input from stdin */ args[3] = "-i"; /* Run as an interactive shell */ args[4] = NULL; /* Build the environ array for the child */ sprintf(home_var, "HOME=%s", cpw->pw_dir); sprintf(logname_var, "LOGNAME=%s", cpw->pw_name); envs[0] = home_var; envs[1] = logname_var; envs[2] = path_var; envs[3] = stdio_var; envs[4] = terminal_type_var; envs[5] = nlspath_var; envs[6] = NULL; /* Set up inheritance structure */ memset(&inherit, '\0', sizeof(struct inheritance)); inherit.flags = SPAWN_SETTHREAD_NP; inherit.pgroup = SPAWN_NEWPGROUP; /* Change to the home directory for the client. The child process inherit this as its current working directory. */ chdir(cpw->pw_dir); /* Start a child process running the shell interpreter */ if(spawn(args[0], fd_count, fd_map, &inherit, args, envs) < 0){ LogError("Could not start qsh process , spawn() failed : %s\n", strerror(errno)); printf("errno = %d: %s\n", errno, strerror(errno)); SendError(cfd, "Could not start qsh process by spawn error.\n"); } printf("spawn success !\n"); /* Clean up for the next connection */ chdir(server_dir); close(cfd); printf("close cfd.\n"); /* Switch back to server's user profile */ QWTSETP(server_ph, &error); if(error.Bytes_Available != 0){/* ApiErr */ LogError("Could not switch back to server's profile, " "QWTSETP() failed with exception %7.7s\n", error.Exception_Id); break; }/* ApiErr */ }/*while*/ /* Clean up */ printf("close sfd.\n"); close(sfd); #pragma disable_handler /* Exception handler */ #pragma disable_handler /* Cancel handler */ printf("* exit(0)\n"); exit(0); return(0); /* Exception handler */ Cleanup: LogError("Unexpected exception %7.7s\n", ca.Msg_Id); close(sfd); exit(1); } /****************************/ int strtoupper(char *string) /****************************/ { for( ; *string != '\0'; ++string){/*for-loop*/ *string = toupper(*string); }/*for-loop*/ return 0; } /**************************************************/ int GetString(int fd, char *buffer, size_t nbytes) /**************************************************/ { char c; do{ if(read(fd, &c, 1) != 1){/* read */ return FALSE; }/* read */ *buffer ++ = c; if(--nbytes == 0){ return TRUE; } } while(c != '\0'); return TRUE; } /*******************************/ void LogError(char *format, ...) /*******************************/ { va_list ap; time_t now; /* Time stamp */ printf("%s%s\n", format, ap); /* If needed, open the log file */ if(log_fp == NULL){ log_fp = fopen(log_file, "w"); if(log_fp == NULL){ return; } } /* Write timestamp to the log file */ now = time(NULL); fprintf(log_fp, format, ap); va_end(ap); /* Flush output to log file */ fflush(log_fp); return; } /*****************************************/ void SendError(int fd, char *format, ...) /*****************************************/ { va_list ap; /* Build the formatted string */ va_start(ap, format); /*vsprintf(log_buffer, format, ap); */ sprintf(log_buffer, ">%s%s", format, ap); /* Write the formatted string */ write(fd, log_buffer, strlen(log_buffer)); return; } /*************************************************/ void ClearHandler(_CNL_Hndlr_Parms_T *cancel_info) /*************************************************/ { int sfd; sfd = *((int*)cancel_info->Com_Area); close(sfd); }