/* nwconn.c 19-Oct-96 */ /* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "net.h" #include #include "nwvolume.h" #include "nwfile.h" #include "connect.h" #include "nwqueue.h" static char **build_argv(char *buf, int bufsize, char *command) /* routine returns **argv for use with execv routines */ /* buf will contain the path component */ { int len = strlen(command); int offset = ((len+4) / 4) * 4; /* aligned offset for **argv */ int components = (bufsize - offset) / 4; if (components > 1) { /* minimal argv[0] + NULL */ char **argv = (char **)(buf+offset); char **pp = argv; char *p = buf; char c; int i=0; --components; memcpy(buf, command, len); memset(buf+len, 0, bufsize - len); *pp = p; while ((0 != (c = *p++)) && i < components) { if (c == 32 || c == '\t') { *(p-1) = '\0'; if (*p != 32 && *p != '\t') { *(++pp)=p; i++; } } else if (!i && c == '/') { /* here i must get argv[0] */ *pp=p; } } XDPRINTF((5, 0, "build_argv, path='%s'", buf)); pp=argv; while (*pp) { XDPRINTF((5, 0, "build_argv, argv='%s'", *pp)); pp++; } return(argv); } return(NULL); } static void close_piped(int piped[3][2]) { int j=3; while (j--) { int k=2; while (k--) { if (piped[j][k] > -1){ close(piped[j][k]); piped[j][k] = -1; } } } } static void err_close_pipe(FILE_PIPE *fp, int lpid, int j, int piped[3][2]) { while (j--) if (fp->fildes[j]) fclose(fp->fildes[j]); close_piped(piped); kill(lpid, SIGTERM); kill(lpid, SIGQUIT); waitpid(lpid, NULL, 0); kill(lpid, SIGKILL); } static int x_popen(char *command, int uid, int gid, FILE_PIPE *fp) { int piped[3][2]; int lpid=-1; int j=3; char buf[300]; char **argv=build_argv(buf, sizeof(buf), command); if (argv == NULL) return(-1); while (j--){ int k=2; while(k--) piped[j][k] = -1; } if (! (pipe(&piped[0][0]) > -1 && pipe(&piped[1][0]) > -1 && pipe(&piped[2][0]) > -1 && (lpid=fork()) > -1)) { close_piped(piped); return(-1); } if (lpid == 0) { /* Child */ signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGHUP, SIG_DFL); j=3; while(j--) close(j); j=3; while(j--) { int x = (j) ? 0 : 1; int x_ = (j) ? 1 : 0; close(piped[j][x] ); dup2( piped[j][x_], j); close(piped[j][x_] ); } if (uid > -1 || gid > -1) { seteuid(0); if (gid > -1) setgid(gid); if (uid > -1) setuid(uid); if (gid > -1) setegid(gid); if (uid > -1) seteuid(uid); } execvp(buf, argv); exit(1); /* Never reached I hope */ } j=-1; while (++j < 3) { int x = (j) ? 0 : 1; int x_ = (j) ? 1 : 0; close(piped[j][x_]); piped [j][x_] = -1; fp->fildes [j] = fdopen(piped[j][x], ( (j) ? "r" : "w") ); if (NULL == fp->fildes[j]){ err_close_pipe(fp, lpid, j+1, piped); return(-1); } } return(lpid); } int ext_pclose(FILE_PIPE *fp) { int status=-1; void (*intsave) (int) = signal(SIGINT, SIG_IGN); void (*quitsave)(int) = signal(SIGQUIT, SIG_IGN); void (*hupsave) (int) = signal(SIGHUP, SIG_IGN); int j = 3; while (j--) if (fp->fildes[j]) fclose(fp->fildes[j]); if (fp->command_pid != waitpid(fp->command_pid, &status, 0)) { kill(fp->command_pid, SIGTERM); waitpid(fp->command_pid, &status, 0); } kill(fp->command_pid, SIGKILL); signal(SIGINT, intsave); signal(SIGQUIT, quitsave); signal(SIGHUP, hupsave); xfree(fp); return(status); } FILE_PIPE *ext_popen(char *command, int uid, int gid) { FILE_PIPE *fp=(FILE_PIPE*) xcmalloc(sizeof(FILE_PIPE)); void (*intsave) (int) = signal(SIGINT, SIG_IGN); void (*quitsave)(int) = signal(SIGQUIT, SIG_IGN); void (*hupsave) (int) = signal(SIGHUP, SIG_IGN); if ((fp->command_pid = x_popen(command, uid, gid, fp)) < 0) { xfree(fp); fp=NULL; XDPRINTF((1, 0, "ext_popen failed:command='%s'", command)); } signal(SIGINT, intsave); signal(SIGQUIT, quitsave); signal(SIGHUP, hupsave); return(fp); } /* minimal queue handling to enable simple printing */ #define MAX_JOBS 5 /* max. open queue jobs for one connection */ static int anz_jobs=0; typedef struct { uint32 fhandle; int old_job; /* is old structure */ union { QUEUE_JOB n; QUEUE_JOB_OLD o; } q; } INT_QUEUE_JOB; INT_QUEUE_JOB *queue_jobs[MAX_JOBS]; static INT_QUEUE_JOB *give_new_queue_job(int old_job) { int k=-1; while (++k < anz_jobs) { INT_QUEUE_JOB *p=queue_jobs[k]; if (!p->fhandle) { /* free slot */ memset(p, 0, sizeof(INT_QUEUE_JOB)); p->old_job = old_job; if (old_job) p->q.o.job_id[0] = k+1; else p->q.n.job_id[0] = k+1; return(p); } } if (anz_jobs < MAX_JOBS) { INT_QUEUE_JOB **pp=&(queue_jobs[anz_jobs++]); *pp = (INT_QUEUE_JOB *) xmalloc(sizeof(INT_QUEUE_JOB)); memset(*pp, 0, sizeof(INT_QUEUE_JOB)); (*pp)->old_job = old_job; if (old_job) (*pp)->q.o.job_id[0] = anz_jobs; else (*pp)->q.n.job_id[0] = anz_jobs; return(*pp); } return(NULL); } static void free_queue_job(int q_id) { if (q_id > 0 && q_id <= anz_jobs) { INT_QUEUE_JOB **pp=&(queue_jobs[q_id-1]); uint32 fhandle = (*pp)->fhandle; if (fhandle > 0) nw_close_file(fhandle, 1); if (q_id == anz_jobs) { xfree(*pp); --anz_jobs; } else (*pp)->fhandle=0L; } } static void set_entry_time(uint8 *entry_time) { struct tm *s_tm; time_t timer; time(&timer); s_tm = localtime(&timer); entry_time[0] = (uint8) s_tm->tm_year; entry_time[1] = (uint8) s_tm->tm_mon+1; entry_time[2] = (uint8) s_tm->tm_mday; entry_time[3] = (uint8) s_tm->tm_hour; entry_time[4] = (uint8) s_tm->tm_min; entry_time[5] = (uint8) s_tm->tm_sec; } static int create_queue_file(uint8 *job_file_name, uint32 q_id, int jo_id, int connection, uint8 *dirname, int dir_nam_len, uint8 *job_bez) { int result; *job_file_name = sprintf((char*)job_file_name+1, "%07lX%d.%03d", q_id, jo_id, connection); seteuid(0); result=nw_alloc_dir_handle(0, dirname, dir_nam_len, 99, 2, 1); if (result > -1) { char unixname[300]; result=conn_get_kpl_unxname(unixname, result, job_file_name+1, (int) *job_file_name); if (result > -1) { struct stat stbuff; result=file_creat_open(result, (uint8*)unixname, &stbuff, 0x6, 0x6, 1|4|8, 0); if (result > -1) { chown(unixname, act_uid, act_gid); chmod(unixname, 0660); } } } reset_guid(); XDPRINTF((5,0,"creat queue file bez=`%s` handle=%d", job_bez, result)); return(result); } int nw_creat_queue(int connection, uint8 *queue_id, uint8 *queue_job, uint8 *dirname, int dir_nam_len, int old_call) { INT_QUEUE_JOB *jo = give_new_queue_job(old_call); uint32 q_id = GET_BE32(queue_id); int result = -0xff; XDPRINTF((5,0,"NW_CREAT_Q:dlen=%d, dirname=%s", dir_nam_len, dirname)); if (NULL != jo) { int jo_id = 0; if (jo->old_job) { jo_id = (int) jo->q.o.job_id[0]; memcpy(&(jo->q.o), queue_job, sizeof(QUEUE_JOB_OLD)); jo->q.o.job_id[0] = (uint8) jo_id; jo->q.o.client_connection = (uint8)connection; jo->q.o.client_task = (uint8)0xfe; /* ?? */ U32_TO_BE32(1, jo->q.o.client_id); /* SU */ set_entry_time(jo->q.o.job_entry_time); jo->q.o.job_typ[0] = 0x0; /* 0xd0;*/ jo->q.o.job_typ[1] = 0x0; jo->q.o.job_position = 0x1; jo->q.o.job_control_flags |= 0x20; result = create_queue_file(jo->q.o.job_file_name, q_id, jo_id, connection, dirname, dir_nam_len, jo->q.o.job_bez); if (result > -1) { jo->fhandle = (uint32) result; U16_TO_BE16(0, jo->q.o.job_file_handle); U32_TO_32(jo->fhandle, jo->q.o.job_file_handle+2); result = 0; } jo->q.o.server_station = 0; jo->q.o.server_task = 0; U32_TO_BE32(0, jo->q.o.server_id); if (!result) memcpy(queue_job, &(jo->q.o), sizeof(QUEUE_JOB_OLD)); } else { jo_id = (int) jo->q.n.job_id[0]; memcpy(&(jo->q.n), queue_job, sizeof(QUEUE_JOB)); jo->q.n.job_id[0] = (uint8) jo_id; U16_TO_BE16(0xffff, jo->q.n.record_in_use); U32_TO_BE32(0x0, jo->q.n.record_previous); U32_TO_BE32(0x0, jo->q.n.record_next); jo->q.n.client_connection[2] = 0; jo->q.n.client_connection[3] = 0; U16_TO_16(connection, jo->q.n.client_connection); memset(jo->q.n.client_task, 0, 4); jo->q.n.client_task[0] = (uint8)0xfe; /* ?? */ U32_TO_BE32(1, jo->q.n.client_id); /* SU */ set_entry_time(jo->q.n.job_entry_time); jo->q.n.job_typ[0] = 0x0; /* 0xd0;*/ jo->q.n.job_typ[1] = 0x0; jo->q.n.job_position[0] = 0x1; jo->q.n.job_position[1] = 0x0; jo->q.n.job_control_flags[0] |= 0x20; jo->q.n.job_control_flags[1] = 0x0; result = create_queue_file(jo->q.n.job_file_name, q_id, jo_id, connection, dirname, dir_nam_len, jo->q.n.job_bez); if (result > -1) { jo->fhandle = (uint32) result; U32_TO_32(jo->fhandle, jo->q.n.job_file_handle); result = 0; } U32_TO_BE32(0, jo->q.n.server_station); U32_TO_BE32(0, jo->q.n.server_task); U32_TO_BE32(0, jo->q.n.server_id); if (!result) memcpy(queue_job, &(jo->q.n), sizeof(QUEUE_JOB)); } if (result) free_queue_job(jo_id); } return(result); } int nw_close_file_queue(uint8 *queue_id, uint8 *job_id, uint8 *prc, int prc_len) { int result = -0xff; int jo_id = (int) *job_id; /* ever only the first byte */ XDPRINTF((5,0,"nw_close_file_queue JOB=%d", jo_id)); if (jo_id > 0 && jo_id <= anz_jobs){ INT_QUEUE_JOB *jo=queue_jobs[jo_id-1]; int fhandle = (int)jo->fhandle; char unixname[300]; QUEUE_PRINT_AREA qpa; if (jo->old_job) { memcpy(&qpa, jo->q.o.client_area, sizeof(QUEUE_PRINT_AREA)); } else { memcpy(&qpa, jo->q.n.client_area, sizeof(QUEUE_PRINT_AREA)); } strmaxcpy((uint8*)unixname, (uint8*)file_get_unix_name(fhandle), sizeof(unixname)-1); XDPRINTF((5,0,"nw_close_file_queue fhandle=%d", fhandle)); if (*unixname) { char buff[1024]; char printcommand[300]; FILE *f=NULL; if (prc_len && *(prc+prc_len-1)=='!'){ strmaxcpy((uint8*)buff, prc, prc_len-1); sprintf(printcommand, "%s %s %s", buff, qpa.banner_user_name, qpa.banner_file_name); } else strmaxcpy((uint8*)printcommand, prc, prc_len); nw_close_file(fhandle, 1); jo->fhandle = 0L; if (NULL == (f = fopen(unixname, "r"))) { /* OK now we try the open as root */ seteuid(0); f = fopen(unixname, "r"); reset_guid(); } if (NULL != f) { int is_ok = 0; FILE_PIPE *fp = ext_popen(printcommand, geteuid(), getegid()); if (fp) { int k; is_ok++; while ((k = fread(buff, 1, sizeof(buff), f)) > 0) { /* if (1 != fwrite(buff, k, 1, fp->fildes[0])) { */ if (k != write(fileno(fp->fildes[0]), buff, k)) { XDPRINTF((1,0,"Cannot write to pipe `%s`", printcommand)); is_ok=0; } } if (0 != (k=ext_pclose(fp))) { XDPRINTF((1,0,"Errorresult = %d by closing print pipe", k)); } } else XDPRINTF((1,0,"Cannot open pipe `%s`", printcommand)); fclose(f); if (is_ok) { seteuid(0); unlink(unixname); reset_guid(); result=0; } } else XDPRINTF((1,0,"Cannot open queue-file `%s`", unixname)); } else XDPRINTF((2,0,"fhandle=%d NOT OK !", fhandle)); free_queue_job(jo_id); } return(result); }