diff -acrBN orig_samba-3.6.4/source3/librpc/rpc/rpc_common.c samba-3.6.4/source3/librpc/rpc/rpc_common.c *** orig_samba-3.6.4/source3/librpc/rpc/rpc_common.c 2012-04-07 15:23:20.000000000 +0200 --- samba-3.6.4/source3/librpc/rpc/rpc_common.c 2012-05-17 12:50:16.000000000 +0200 *************** *** 35,40 **** --- 35,42 ---- #include "../librpc/gen_ndr/ndr_ntsvcs.h" #include "../librpc/gen_ndr/ndr_epmapper.h" #include "../librpc/gen_ndr/ndr_drsuapi.h" + #include "../librpc/gen_ndr/ndr_atsvc.h" + static const char *get_pipe_name_from_iface( TALLOC_CTX *mem_ctx, const struct ndr_interface_table *interface) *************** *** 140,145 **** --- 142,150 ---- if (!smb_register_ndr_interface(&ndr_table_drsuapi)) { return false; } + if (!smb_register_ndr_interface(&ndr_table_atsvc)) { + return false; + } return true; } diff -acrBN orig_samba-3.6.4/source3/Makefile.in samba-3.6.4/source3/Makefile.in *** orig_samba-3.6.4/source3/Makefile.in 2012-04-07 15:23:20.000000000 +0200 --- samba-3.6.4/source3/Makefile.in 2012-05-16 17:12:56.000000000 +0200 *************** *** 380,385 **** --- 380,387 ---- rpc_client/cli_lsarpc.o \ rpc_client/init_lsa.o + LIBCLI_ATSVC_OBJ = librpc/gen_ndr/ndr_atsvc_c.o + LIBCLI_SAMR_OBJ = librpc/gen_ndr/ndr_samr_c.o \ rpc_client/cli_samr.o *************** *** 401,406 **** --- 403,409 ---- librpc/gen_ndr/ndr_dssetup.o \ librpc/gen_ndr/ndr_epmapper.o \ librpc/gen_ndr/ndr_ntsvcs.o \ + librpc/gen_ndr/ndr_atsvc.o \ $(LIBNDR_SPOOLSS_OBJ) # this includes only the low level parse code, not stuff *************** *** 1042,1048 **** rpcclient/cmd_shutdown.o rpcclient/cmd_test.o \ rpcclient/cmd_wkssvc.o rpcclient/cmd_ntsvcs.o \ rpcclient/cmd_drsuapi.o rpcclient/cmd_eventlog.o \ ! rpcclient/cmd_winreg.o \ $(DISPLAY_SEC_OBJ) RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \ --- 1045,1051 ---- rpcclient/cmd_shutdown.o rpcclient/cmd_test.o \ rpcclient/cmd_wkssvc.o rpcclient/cmd_ntsvcs.o \ rpcclient/cmd_drsuapi.o rpcclient/cmd_eventlog.o \ ! rpcclient/cmd_winreg.o rpcclient/cmd_at.o\ $(DISPLAY_SEC_OBJ) RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \ *************** *** 1064,1069 **** --- 1067,1073 ---- $(LIBCLI_SAMR_OBJ) \ $(LIBCLI_WINREG_OBJ) \ $(LIBCLI_NETLOGON_OBJ) \ + $(LIBCLI_ATSVC_OBJ) \ $(RPC_CLIENT_SCHANNEL_OBJ) \ rpc_client/init_netlogon.o \ rpc_client/init_samr.o diff -acrBN orig_samba-3.6.4/source3/rpcclient/cmd_at.c samba-3.6.4/source3/rpcclient/cmd_at.c *** orig_samba-3.6.4/source3/rpcclient/cmd_at.c 1970-01-01 01:00:00.000000000 +0100 --- samba-3.6.4/source3/rpcclient/cmd_at.c 2012-05-17 15:42:01.000000000 +0200 *************** *** 0 **** --- 1,610 ---- + /* + Unix SMB/CIFS implementation. + RPC pipe client + + Parts cloned from samba-tng project. + + Copyright (C) niekt0@hysteria.sk 2012 + Copyright (C) Günther Deschner 2008 + + 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 3 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, see . + */ + + #include "includes.h" + #include "rpcclient.h" + #include "../librpc/gen_ndr/ndr_atsvc_c.h" + #include "../librpc/gen_ndr/ndr_srvsvc_c.h" /* needed for "at NOW" */ + #include "librpc/gen_ndr/libnetapi.h" /* for ERROR_MORE_DATA */ + + + char *daynames[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + char *daynames_short[] = { "M", "Tu", "W", "Th", "F", "Sa", "Su" }; + enum action_type {ACTION_HEADER, ACTION_ENUMERATE, ACTION_FOOTER}; + + #define MAX_COMMAND_LEN 4096 /* hard-coded */ + #define SOON_OFFSET 60 /* seconds */ + #define DAY_MSEC 86399999 /* max daytime (in msec) */ + /* == (24*60*60*1000-1), from M$ documentation. */ + + #define HELP_TEXT "HELP for `at':\n"\ + "\tScheduler control (at /? for syntax)\n"\ + "at { {time | NOW} [/INTERACTIVE] [{/EVERY|/NEXT}:5,Sun,...] command\n"\ + "\t| [/DEL] [jobid] }\n\n" + + + static char *get_at_time_str(uint32 t) + { + static fstring timestr; + unsigned int hours, minutes, seconds; + + hours = t / 1000; + seconds = hours % 60; + hours /= 60; + minutes = hours % 60; + hours /= 60; + + slprintf(timestr, sizeof(timestr)-1, "%2d:%02d:%02d", + hours, minutes, seconds); + + return timestr; + } + + static char *get_at_days_str(uint32 monthdays, uint8 weekdays, uint8 flags) + { + static fstring days; + fstring numstr; + int day, bit; + int first = True; + + if (monthdays == 0 && weekdays == 0) + return "Once"; + + if (flags & JOB_RUN_PERIODICALLY) + { + + if (((weekdays)&(0x7F))==(0x7F)) + return "Every Day"; + + fstrcpy(days, "Every "); + } + else + { + fstrcpy(days, "Next "); + } + + for (day = 1, bit = 1; day < 32; day++, bit <<= 1) + { + if (monthdays & bit) + { + if (first) + first = False; + else + fstrcat(days, ", "); + + slprintf(numstr, sizeof(numstr)-1, "%d", day); + fstrcat(days, numstr); + } + } + + for (day = 0, bit = 1; day < 7; day++, bit <<= 1) + { + if (weekdays & bit) + { + if (first) + first = False; + else + fstrcat(days, ", "); + + fstrcat(days, daynames_short[day]); + } + } + + return days; + } + + + /**************************************************************************** + display scheduled jobs + ****************************************************************************/ + void display_at_enum_info(enum action_type action, struct atsvc_enum_ctr jobs) + { + switch (action) + { + case ACTION_HEADER: + { + if (jobs.entries_read == 0) + { + printf("\tNo Jobs.\n"); + } + else + { + printf("\tJobs:\n"); + printf("\t-----\n"); + } + break; + } + case ACTION_ENUMERATE: + { + int i; + + for (i = 0; i < jobs.entries_read; i++) + { + printf("\t%d\t%s\t%s\t%s\n", + jobs.first_entry[i].job_id, + get_at_time_str(jobs.first_entry[i].job_time), + get_at_days_str(jobs.first_entry[i].days_of_month, + jobs.first_entry[i].days_of_week, + jobs.first_entry[i].flags), + jobs.first_entry[i].command); + } + + break; + } + case ACTION_FOOTER: + { + printf("\n"); + break; + } + } + } + + + /**************************************************************************** + display information about a scheduled job + ****************************************************************************/ + void display_at_job_info(enum action_type action, struct atsvc_JobInfo *const job) + { + switch (action) + { + case ACTION_HEADER: + { + printf("\tJob Information:\n"); + printf("\t----------------\n"); + break; + } + case ACTION_ENUMERATE: + { + printf("\tTime: %s\n", + get_at_time_str(job->job_time)); + + printf("\tSchedule: %s\n", + get_at_days_str(job->days_of_month, job->days_of_week, + job->flags)); + + printf("\tStatus: %s", + (job->flags & JOB_EXEC_ERROR) ? "Failed" : "OK"); + + if (job->flags & JOB_RUNS_TODAY) + { + printf(", Runs Today"); + } + + printf("\n\tInteractive: %s\n", + (job->flags & JOB_NONINTERACTIVE) ? "No" + : "Yes"); + + printf("\tCommand: %s\n", job->command); + break; + } + case ACTION_FOOTER: + { + printf("\n"); + break; + } + } + } + + + /**************************************************************************** + checks for a /OPTION:param style option + ****************************************************************************/ + static int checkopt(const char *input, const char *optname, char **params) + { + char *inend; + + if (*input++ != '/') + return False; + + for (inend = (char *) input; + *inend != 0 && *inend != ':'; + inend++); + + if (params != NULL) + { + *params = inend; + } + + return strnequal(input, optname, inend - input); + } + + /**************************************************************************** + parses a list of days of the week and month + ****************************************************************************/ + static int at_parse_days(char *str, uint32 *monthdays, uint8 *weekdays) + { + char *tok; + char *nexttok = str; + int day; + + do { + tok = nexttok; + + if ((nexttok = strchr(tok, ',')) != NULL) + { + *nexttok++ = 0; + } + + if (isdigit((int)*tok)) + { + day = strtol(tok, NULL, 10); + if (day == 0 || day > 31) + { + printf("\tInvalid day of month.\n\n"); + return False; + } + + *monthdays |= (1 << (day-1)); + } + else + { + if (strlen(tok) < 3) + { + for (day = 0; day < 7; day++) + { + if (!StrnCaseCmp(tok, daynames_short[day],2)) + break; + } + } + else + { + for (day = 0; day < 7; day++) + { + if (!StrnCaseCmp(tok, daynames[day], 3)) + break; + } + } + + if (day < 7) + { + *weekdays |= (1 << day); + } + else + { + printf("\tInvalid day of week\n\n"); + return False; + } + } + + } while (nexttok != NULL); + + return True; + } + + + /**************************************************************************** + scheduler add job + ****************************************************************************/ + static WERROR cmd_at(struct rpc_pipe_client *info, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) + { + int add = False; + int del = False; + char *p; + + char command[MAX_COMMAND_LEN]; + + unsigned int hours=0, minutes =0, seconds = 0; + uint32 jobid = -1; + uint8 flags = JOB_NONINTERACTIVE; + NTSTATUS status1, status2; + int i=0; + + struct atsvc_JobInfo job; + struct dcerpc_binding_handle *b = info->binding_handle; + memset(&job,0,sizeof(job)); + + + + while (argc > 1) + { + argc--; + argv++; + + if (checkopt(argv[0], "?", NULL)) + { + printf(HELP_TEXT); + return ntstatus_to_werror(NT_STATUS_OK); + } + + if (checkopt(argv[0], "DELETE", NULL)) + { + del = True; + continue; + } + else if (checkopt(argv[0], "YES", NULL)) + { + /* Compatibility */ + continue; + } + + jobid = strtol(argv[0], &p, 10); + if (*p == 0) /* Entirely numeric field */ + continue; + + if (!StrnCaseCmp(argv[0], "NOW",3)) /* hackish, but useful */ + { + NTSTATUS status3; + struct rpc_pipe_client *pipe_cli2 = NULL; + struct dcerpc_binding_handle *b2 =NULL; + struct srvsvc_NetRemoteTODInfo *tod; + WERROR staterr; + + memset(&tod,0,sizeof(tod)); + + /* We need to make new pipe (srvsvc) */ + status3 = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(info), + &ndr_table_srvsvc.syntax_id,&pipe_cli2); + b2 = pipe_cli2->binding_handle; + + /* get server time */ + status1 = dcerpc_srvsvc_NetRemoteTOD(b2, mem_ctx, + info->srv_name_slash, + &tod, + &staterr); + + if (!NT_STATUS_IS_OK(status1)) { + return ntstatus_to_werror(status1); + } + if (!W_ERROR_IS_OK(staterr)) { + return staterr; + } + + /* time in msec from start of the day. */ + /* SOON_OFFSET is hack, default 60 sec. */ + job.job_time= (((((tod->hours - (tod->timezone/60)) * 60) + + tod->mins) * 60) + + tod->secs + SOON_OFFSET) * 1000; + + /* midnight overflow */ + if (job.job_time > DAY_MSEC ) { + job.job_time-= DAY_MSEC; + } + + } + else if (sscanf(argv[0], "%d:%d:%d", &hours, &minutes, &seconds) >= 2) + { + p = strchr(argv[0], 0); + + if (!StrnCaseCmp(p-2, "AM",2)) + { + hours = (hours == 12) ? 0 : hours; + } + + if (!StrnCaseCmp(p-2, "PM",2)) + { + hours = (hours == 12) ? 12 : hours + 12; + } + + if (hours > 23 || minutes > 59 || seconds > 59) + { + printf("\tInvalid time.\n\n"); + return ntstatus_to_werror(NT_STATUS_INVALID_PARAMETER); + } + } + else + { + printf("Syntax error. Try \"help at\".\n"); + return ntstatus_to_werror(NT_STATUS_OK); + } + + add = True; + command[0] = 0; + p = NULL; + + if (argc <= 1) break; + argc--; + argv++; + + if (checkopt(argv[0], "INTERACTIVE", NULL)) + { + flags &= ~JOB_NONINTERACTIVE; + + if (argc <= 1) break; + argc--; + argv++; + } + + if (checkopt(argv[0], "EVERY", &p)) + { + flags |= JOB_RUN_PERIODICALLY; + } + else + { + checkopt(argv[0], "NEXT", &p); + } + + if (p != NULL) + { + if (*p == ':') + { + if (!at_parse_days(p+1, &job.days_of_month, &job.days_of_week)) + return ntstatus_to_werror(NT_STATUS_INVALID_PARAMETER); + } + else + { + job.days_of_week = 0x7F; + } + + if (argc <= 1) break; + argc--; + argv++; + } + + while (True) + { + strncat(command, argv[0], sizeof(command)); + + if (argc <= 1) break; + argc--; + argv++; + + strncat(command, " ", sizeof(command)); + } + + break; + } + + if (add && !command[0]) + { + printf("\tNo command specified.\n\n"); + return ntstatus_to_werror(NT_STATUS_INVALID_PARAMETER); + } + + if (add) /* add job */ + { + + if (job.job_time == 0) { /* time not set to NOW */ + job.job_time = ((((hours * 60) + minutes) * 60) + + seconds) * 1000; + } + job.flags = flags; + job.command = command; + + status1=dcerpc_atsvc_JobAdd(b, + mem_ctx, + info->srv_name_slash, + &job, + &jobid, + &status2); + + if (NT_STATUS_IS_OK(status1)) + + { + printf("\tJob ID: %d\n\n", jobid); + + } else { + printf("Error: something is wrong (0x%x)\n", + ntstatus_to_werror(status1)); + return ntstatus_to_werror(status1); + } + } + + else if (del) /* delete */ + { + if (jobid == -1) + { + printf("\tDeleting all jobs.\n\n"); + status1=dcerpc_atsvc_JobDel(b, + mem_ctx, + info->srv_name_slash, + 0, + 0xffffffff, + &status2); + } + else + { + printf("\tDeleting job %d.\n\n", jobid); + status1=dcerpc_atsvc_JobDel(b, + mem_ctx, + info->srv_name_slash, + jobid, + jobid, + &status2); + } + + } + + else if (jobid == -1) /* enumerate */ + { + struct atsvc_enum_ctr jobs; + uint32_t resume_handle=0; + uint32 num_jobs = 0; + + jobs.first_entry=NULL; + jobs.entries_read=0; + + status2=werror_to_ntstatus(WERR_MORE_DATA); + /* ERROR_MORE_DATA ?? */ + + while (W_ERROR_EQUAL(ntstatus_to_werror(status2),WERR_MORE_DATA)) { + status1=dcerpc_atsvc_JobEnum(b, + mem_ctx, + info->srv_name_slash, + &jobs, + 0, + &num_jobs, + &resume_handle, + &status2); + + if (!NT_STATUS_IS_OK(status1) ) { + printf("Error: something is wrong (0x%x)\n", + ntstatus_to_werror(status1)); + return ntstatus_to_werror(status1); + } + + if (!(W_ERROR_EQUAL(ntstatus_to_werror(status2),WERR_MORE_DATA) + || NT_STATUS_IS_OK(status2))) + { + printf("Error: something is wrong (0x%x)\n", + ntstatus_to_werror(status2)); + return ntstatus_to_werror(status2); + } + + display_at_enum_info(ACTION_HEADER , jobs); + display_at_enum_info(ACTION_ENUMERATE, jobs); + display_at_enum_info(ACTION_FOOTER , jobs); + + /* talloc should free this for us */ + jobs.first_entry=NULL; + + } + } + + else /* job info */ + { + struct atsvc_JobInfo *job; + + status1=dcerpc_atsvc_JobGetInfo(b, + mem_ctx, + info->srv_name_slash, + jobid, + &job, + &status2); + if (NT_STATUS_IS_OK(status1)) + { + if (NT_STATUS_IS_OK(status2)) { + display_at_job_info(ACTION_HEADER , job); + display_at_job_info(ACTION_ENUMERATE, job); + display_at_job_info(ACTION_FOOTER , job); + } else { + printf("Error: No such job (0x%x).\n", + ntstatus_to_werror(status2)); + return ntstatus_to_werror(status2); + } + } + } + + return ntstatus_to_werror(NT_STATUS_OK); + } + + struct cmd_set at_commands[] = { + + { "ATSVC" }, + { "at", RPC_RTYPE_WERROR, NULL, cmd_at, &ndr_table_atsvc.syntax_id, + NULL, "Maintain scheduler: Add/Del/list jobs", HELP_TEXT}, + { NULL } + }; + diff -acrBN orig_samba-3.6.4/source3/rpcclient/rpcclient.c samba-3.6.4/source3/rpcclient/rpcclient.c *** orig_samba-3.6.4/source3/rpcclient/rpcclient.c 2012-04-07 15:23:20.000000000 +0200 --- samba-3.6.4/source3/rpcclient/rpcclient.c 2012-05-16 14:54:29.000000000 +0200 *************** *** 615,620 **** --- 615,621 ---- extern struct cmd_set test_commands[]; extern struct cmd_set wkssvc_commands[]; extern struct cmd_set ntsvcs_commands[]; + extern struct cmd_set at_commands[]; extern struct cmd_set drsuapi_commands[]; extern struct cmd_set eventlog_commands[]; extern struct cmd_set winreg_commands[]; *************** *** 633,638 **** --- 634,640 ---- shutdown_commands, test_commands, wkssvc_commands, + at_commands, ntsvcs_commands, drsuapi_commands, eventlog_commands,