summaryrefslogtreecommitdiff
path: root/examples/rpcclient/ntsd.c
blob: 37976edaa5e53565a1c6c95fcaeb5dc4ff2d9624 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* This is an experiemental programme to shutdown a  group of NTws in a 
   Samba domain via rpcclient.

   Copyright (c) David Bannon 1999
   David Bannon, D.Bannon@latrobe.edu.au, 4th November, 1999 

   Full permission is granted to use this code (for what that is worth) in
   any way you wish, strictly at your own risk.

   I use it from a cron a job to close a computer lab down at 5:00 pm.
 
   It has some serious security implications, make sure you understand 
   them before using this code !

   If you find a way to make this 'power down' a machine that is set up to 
   do power down correctly please let me know !!   

    Machines to be shutdown must be members of a samba (or NT) domain.
    You are going to have to offer your domain admin user name/password
    (see below).

    As you probably don't want your domain admin password appearing in the 
    crontab file or popping up in a 'ps' list, it can be encrypted and the 
    programme will tell you what it should look like. i.e :

        [root@bclab shutdown]# ./ntsd -e
        Domain Admin User name :dbannon
        Domain Admin Password
        Use the string between [] after a -p : [1HCeTcXqOfo7R[hg]
        [root@bclab shutdown]#

    Now a crontab entry would look like this :

        00 17 * * 1-5 /usr/local/sbin/ntsd -p'1HCeTcXqOfo7R[hg' -a

        The -p indicates passwd (actually user name and password) and the
        -a says shutdown all machines. Note that the password string must
        have inverted commas around it so the shell does not try and expand
        any special charachers that it is likely to contain.
        
    Security Alert !!
        The encryption is pretty weak and its reversable ! Change the key
        strings, compile and change the key strings again ! You don't need
        to remember the key but if you leave the unchanged source around 
        someone may use it to reverse the encryption. The Keys are in lumps
        to stop someone doing a 'cat ntsd' and seeing the key string. 
	   (yeah, I know its not very clever, but they should not be able to
	    read the binary or your crontab anyway) 

    Ping
        I ping the target machines before trying to shut them down, you
        dont't need to, just let rpcclient time out. If you want to ping
        first (because its nicer !) you need :
        1. First element of IP name should be the netbios name. (makes sense)
        2. If the server you will run the cron job from does not have the
           same default domain name as machines being shutdown then you will
           need to define USE_DOMAIN and put in appropriate ip domain info.
        This code does ping, get busy with vi if you don't want to.

    Machine Names
        For this system to be practical, the machine names must be in some 
        sort of sequence, ie bclab1, bclab2, bclab3, not more creative like
        grumpy, dopey, sneezy. See the code in main() to see how the names
        are built.

    Configuration

      Machine Names
        If you have used a naming scheme like mine then you may need to 
        change only LASTMACHINE and PREFIX, otherwise look at main(). 

      Binary locations.
        We need to find the rpcclient and ping binaries. The values below
        are typical. Better check first. 

      Compile
        Known to compile cleanly on linux (RH5.0 - RH6.1) and DEC 4.0. Does
        not do anything fancy so should compile on most systems easily 
        enough.

      Install
        Rename the binary (ie ntsd) and put it somewhere safe. It should 
        be rwx root only. Comes up with basic help if run without command
        line switch, prompts for admin user name and password if used 
        without the -p switch.
        (Typically)Put entry in your crontab (crontab -e) and watch the
        fun. Remember, it does not keep them shutdown, try an entry every
        5 minutes for a while (or until door is locked).
*/
                 

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pwd.h>

#define PING "/bin/ping"
#define RPCCLIENT "/usr/local/samba/bin/rpcclient" 


#define LASTMACHINE 14               /* ie, scans bclab1 through to bclab14 */
#define PREFIX "bclab"

/*    #define USE_DOMAIN    Only if you need full ip name to ping machines */

#ifdef USE_DOMAIN
#define DOMAIN ".biochem.latrobe.edu.au"     /* required by ping, possibly.
 */
#endif

#define KEY1 "Please"
#define KEY2 "don't leave"
#define KEY3 "this"
#define KEY4 "as it is"
#define KEY5 "here"
#define KEY6 "silly."


int Shutdown(char *machine, char *PassWord) {
    char Buff[128], *Ptr;
    int Res;
    /* printf("Shutting down %s\n", machine); */
    sprintf(Buff, "/bin/ping -c 1 -q %s > /dev/null", machine);
    Res = system(Buff);
    if (Res == 0) {             /* its turned on */
        Ptr = machine;
         /* first 'word' in ip name = netbios name, get rid of rest */
        while (*++Ptr != 0) if (*Ptr == '.') *Ptr = 0; 
        printf("Shutting down %s\n", machine); 
        sprintf(Buff, "%s -c shutdown -U%s -S %s", RPCCLIENT, PassWord,
machine);
        system(Buff);
    }   
}

int Usage(char *prog) {
    printf("Programme to shutdown NTs in domain.\n");
    printf("Normally called from cron (using encrypted passwd, see -e and
-p).\n");
    printf("Usage    \n");
    printf("    -a             shutdown all machines %s1 to %s%d. \n", 
                                                PREFIX, PREFIX, LASTMACHINE);
    printf("    -m machine     shutdown [machine] (might need full ip
name).\n");
    printf("    -e             tell me my encrypted name and password to
use with -p.\n");
    printf("    -p'pw_string'  use encrypted name & password as given by
-e.\n");
    printf("                   You must have single inverted commas around
the pw string !");
    printf("    -h             help, give this message.\n");
    printf("Typical cron line :  00 17 * * 1-5 /usr/local/sbin/ntsd
-p1HCeTcXqOfo7R[hg -a\n");
    printf("                                                  David Bannon,
Nov 1999\n");
    exit(0);
}	

int GetPassWord(char *Passwd) {
    char *ptr, *p;
    char User[128];
    printf("Domain Admin User name :");
    fgets(User, 127, stdin);
    if (strlen(User) < 3) {
        printf("Short user name, exiting.\n");
        exit(1);
    }
    p = User;
    while (*p != '\n') p++;     /* get rid of newline */
    *p = 0;
    ptr = getpass("Domain Admin Password ");
    if (strlen(ptr) < 3) {
        printf("Short password, exiting.\n");
        exit(1);
    }
    strcpy(Passwd, User);       /* do this with sprintf */
    strcat(Passwd, "%");
    strcat(Passwd, ptr);
    *ptr = 0;                   /* clean up system buffer */
    return 0;
}

int Encrypt(char *InPass) {
    char Pass[128], Enc[128];
    int Temp;
    char *Hash;
    int Offset = 0;
    Hash = malloc(256);
                        /* so it a bit harder than just 'cat ntsd'  */
    sprintf(Hash, "%s%s%s%s%s%s", KEY4, KEY3, KEY2, KEY5, KEY1, KEY6);
    if (InPass == 0) {
        GetPassWord(Pass);          /* may not return */
        while (*(Pass + Offset) != 0) {
            Temp = *(Pass + Offset) + *(Hash + Offset) - ' ';
            if (Temp > '~') Temp = Temp - 95;
            *(Pass+Offset++) = Temp;
        }
        printf("Use the string between [] after a -p : ['%s']\n", Pass);
        exit(0);
    } else {
        while (*(InPass + Offset) != 0) {
            Temp = *(InPass + Offset) - *(Hash + Offset) + ' ';
            if (Temp < ' ') Temp = Temp + 95;
            *(InPass+Offset++) = Temp;
        }
    }
    free(Hash);
    return 0;
}

int main(int argc, char **argv) {
  	extern char *optarg;
  	extern int optind;
	int Ch;
    static char *prog_name;
    int MachineNo = 0, AllMachines = 0;
    char Machine[128], PassWord[128];
    uid_t UID = getuid();
    prog_name = argv[0];
    if (UID != 0) {
        printf("Sorry, this programme can only be run as root.\n");
        exit(1);
    }
    *Machine = 0;
    *PassWord = 0;
    if (argc < 2) Usage(prog_name);
    while ((Ch = getopt(argc, argv, "haem:p:")) != EOF) {
    	switch(Ch) {
    		case 'e': Encrypt(NULL); break;             /* Does not return */
  		    case 'a': AllMachines = 1; break;
   		    case 'm': strcpy(Machine, optarg); break;
		    case 'p': strcpy(PassWord, optarg); break;
		    case 'h': Usage(prog_name); 
		    default: Usage(prog_name);
		}
    }
    if (*PassWord == 0) GetPassWord(PassWord);      /* may not return */
    else Encrypt(PassWord);
    if (*Machine != 0) {
        Shutdown(Machine, PassWord);
        exit(0);
    }
 /* printf("exit for safety = %s.\n", PassWord);
exit(0);  */
    while (++MachineNo < LASTMACHINE+1) {
        pid_t Proc;
#ifdef USE_DOMAIN
        sprintf(Machine, "%s%d%s", PREFIX, MachineNo, DOMAIN);
#else
        sprintf(Machine, "%s%d", PREFIX, MachineNo);
#endif
        Proc = fork();
        if (Proc == 0) {    /* in child process */
            Shutdown(Machine, PassWord);
            exit(0);
        }
    }
    printf("Shutdowns initiated.\n");
}