Archive | Update

09 März 2010 ~ 0 Comments | ÄHNLICHE ARTIKEL

[Update] hMailServer-Konfiguration via CGI

Es ist endlich geschafft! Nachdem ich die letzten Tage überlegt habe, wie ich das ganze am unkompliziertesten löse, habe ich nun eine Möglichkeit gefunden: Die Rede ist von der Verwaltung eines hMailServer Mailaccounts.

In den letzten Tagen hatte ich euch VBScripte vorgestellt, mit denen ein Benutzer sein Passwort ändern oder eine Mailumleitung einrichten. Das Problem bestand bisher, diese Funktionen auch remote verfügbar zu machen – denn direkten Zugriff auf den Server wird keiner der Mailbenutzer kriegen. ;-)

Im Moment verwende ich immernoch einen ziemlich minimalistischen Webserver auf dem Rechner – trotzdem wollte ich die Konfiguration bereits lauffähig machen. Die einzige Möglichkeit hierfür war die Verwendung eines CGI-Scriptes.
Also habe ich mich auf die Suche gemacht, wie ich ein VBScript über CGI ansprechen und ausführen kein. Dummerweise funktionierte das Codebeispiel bei mir überhaupt nicht! Eine andere Lösung musste also her…

…und diese habe ich hier gefunden. Anstatt eines CGI-Scriptes habe ich einfach eine CGI-Anwendung in Delphi geschrieben :D ! Dadurch habe ich zum einen gelernt, wie man sowas macht und zum anderen konnte ich das ganze in einer robusten, mir bekannten Sprache erstellen.

Wo ihr ein bisschen aufpassen müsst, ist bei dem Herleiten der Dateipfade: Irgendwie habe ich da das Gefühl, dass der Server die Werte PATH_INFO, PATH_TRANSLATED und SCRIPT_NAME nicht korrekt setzt. Aber das müsste man nochmal durch das Testen mit anderen Webservern überprüfen.

Hier jedenfalls erstmal der Quelltext:

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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
unit MainForm;

interface

uses
  Windows,
  SysUtils,
  Messages,
  HTTPApp,
  Classes;


type
  TValueAction = (vaUnknown, vaForward, vaPassword);

  TValueRecord = record
    Action         : TValueAction;
    Domain         : String;
    Username       : String;
    Password       : String;
    ForwardAddress : String;
    NewPassword    : String;
  end;

  TMainWebModule = class(TWebModule)
    procedure MainWebModuledefaultAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    { Private-Deklarationen }
    function GetApplicationOutput(AApplication : String; AParameters : TStringList) : String;
    function GetCGIPath(APathTranslated : String; APathInfo : String; AScriptName : String) : String;
    function GetResultString(AAction : TValueAction; AResult : String) : String;
    function GetWindowsPath : String;
    function ParseRequest(ARequest : TWebRequest) : TValueRecord;
  public
    { Public-Deklarationen }
  end;

var
  MainWebModule : TMainWebModule;

implementation

{$R *.xfm}

const
  CCGIFolder       = '/cgi-bin';
  CCscriptExe      = 'system32\cscript.exe';
  CForwardAction   = 'forward';
  CForwardParam    = 'forward';
  CForwardVBS      = 'changeForward.vbs';
  CNewParam        = 'new';
  CNoLogoParam     = '/nologo';
  CPasswordAction  = 'password';
  CPasswordParam   = 'password';
  CPasswordVBS     = 'changePassword.vbs';
  CPathDivider     = '\';
  CQuote           = '"';
  CQuoteEscaped    = '\"';
  CURLDivider      = '/';

// source: http://delphi.about.com/cs/adptips2001/a/bltip0201_2.htm
function TMainWebModule.GetApplicationOutput(AApplication: String; AParameters: TStringList): String;
  function GetParameterLine(AApplication : String; AParameters : TStringList) : String;
  var
    LIndex : Integer;
  begin
    Result := CQuote + StringReplace(AApplication, CQuote, CQuoteEscaped, [rfReplaceAll, rfIgnoreCase]) + CQuote;

    if (AParameters <> nil) then
    begin
      for LIndex := 0 to Pred(AParameters.Count) do
        Result := Result + #32 + CQuote + StringReplace(AParameters[LIndex], CQuote, CQuoteEscaped, [rfReplaceAll, rfIgnoreCase]) + CQuote;
    end;
  end;

  procedure ProcessMessages;
  var
    LMessage : TMsg;
  begin
    while PeekMessage(LMessage, 0, 0, 0, PM_REMOVE) do
    begin
      if (LMessage.Message <> WM_QUIT) then
      begin
        TranslateMessage(LMessage);
        DispatchMessage(LMessage);
      end
      else
        Break;
    end;
  end;
const
  CReadBuffer = 1024;
var
  LAppRunning  : DWord;
  LBuffer      : PChar;
  LBytesRead   : DWord;
  LProcessInfo : TProcessInformation;
  LReadPipe    : THandle;
  LSecurity    : TSecurityAttributes;
  LStart       : TStartUpInfo;
  LWritePipe   : THandle;
begin
  Result := '';

  LSecurity.nLength             := SizeOf(TSecurityAttributes);
  LSecurity.bInheritHandle      := true;
  LSecurity.lpSecurityDescriptor := nil;

  if CreatePipe(LReadPipe, LWritePipe, @LSecurity, 0) then
  begin
    try
      LBuffer := AllocMem(Succ(CReadBuffer));
      try
        FillChar(LStart, SizeOf(LStart), #0) ;
        LStart.cb          := SizeOf(LStart) ;
        LStart.dwFlags     := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
        LStart.hStdInput   := LReadPipe;
        LStart.hStdOutput  := LWritePipe;
        LStart.wShowWindow := SW_HIDE;

        if CreateProcess(nil, PChar(GetParameterLine(AApplication, AParameters)),
                         @LSecurity, @LSecurity, true, NORMAL_PRIORITY_CLASS, nil,
                         nil, LStart, LProcessInfo) then
        begin
          try
            repeat
              LAppRunning := WaitForSingleObject(LProcessInfo.hProcess, 100);
             
              ProcessMessages;
            until (LAppRunning <> WAIT_TIMEOUT);

            repeat
              LBytesRead := 0;
              ReadFile(LReadPipe, LBuffer[0], CReadBuffer, LBytesRead, nil) ;
              LBuffer[LBytesRead] := #0;
              OemToChar(LBuffer, LBuffer);

              Result := Result + String(LBuffer);
            until (LBytesRead < CReadBuffer);
          finally
            CloseHandle(LProcessInfo.hProcess);
            CloseHandle(LProcessInfo.hThread);
          end;
        end;
      finally
        FreeMem(LBuffer);
      end;
    finally
      CloseHandle(LReadPipe);
      CloseHandle(LWritePipe);
    end;
  end;
end;

function TMainWebModule.GetCGIPath(APathTranslated, APathInfo, AScriptName: String): String;
var
  LPosition : Integer;
begin
  Result := '';

  repeat
    LPosition := Pos(CURLDivider, APathInfo);
    if (LPosition > 0) then
      APathInfo[LPosition] := CPathDivider;
  until (LPosition <= 0);

  repeat
    LPosition := Pos(CURLDivider, AScriptName);
    if (LPosition > 0) then
      AScriptName[LPosition] := CPathDivider;
  until (LPosition <= 0);

  if (Pred(Pos(APathInfo, AScriptName) + Length(APathInfo)) = Length(AScriptName)) then
  begin
    Delete(AScriptName, Succ(Length(AScriptName) - Length(APathInfo)), Length(APathInfo));

    if (Pred(Pos(APathInfo, APathTranslated) + Length(APathInfo)) = Length(APathTranslated)) then
    begin
      Delete(APathTranslated, Succ(Length(APathTranslated) - Length(APathInfo)), Length(APathInfo));

      Result := APathTranslated + AScriptName + CPathDivider;
    end;
  end;
end;

function TMainWebModule.GetResultString(AAction: TValueAction; AResult: String) : String;
const
  CEverythingFine   = 'everything went fine';
  CForward          = '(forward)';
  CInternalError    = 'an internal error occured';
  CMissingArguments = 'missing arguments';
  CNoSuchDomain     = 'there is no such domain';
  CPassword         = '(password)';
  CUnknownError     = 'an unknown error occured';
  CWrongCredentials = 'wrong credentials have been provided';
var
  LError  : LongInt;
  LResult : Byte;
begin
  Result := '';

  AResult := Trim(AResult);
  Val(AResult, LResult, LError);
  if (LError = 0) then
  begin
    case AAction of
      vaForward :
      begin
        case LResult of
          0 : Result := AResult + #32 + CEverythingFine + #32 + CForward;
          1 : Result := AResult + #32 + CWrongCredentials + #32 + CForward;
          2 : Result := AResult + #32 + CWrongCredentials + #32 + CForward;
          3 : Result := AResult + #32 + CNoSuchDomain + #32 + CForward;
          4 : Result := AResult + #32 + CWrongCredentials + #32 + CForward;
          5 : Result := AResult + #32 + CInternalError + #32 + CForward;
          6 : Result := AResult + #32 + CMissingArguments + #32 + CForward;
        else
          Result := AResult + #32 + CUnknownError + #32 + CForward;
        end;
      end;

      vaPassword :
      begin
        case LResult of
          0 : Result := AResult + #32 + CEverythingFine + #32 + CPassword;
          1 : Result := AResult + #32 + CWrongCredentials + #32 + CPassword;
          2 : Result := AResult + #32 + CWrongCredentials + #32 + CPassword;
          3 : Result := AResult + #32 + CNoSuchDomain + #32 + CPassword;
          4 : Result := AResult + #32 + CWrongCredentials + #32 + CPassword;
          5 : Result := AResult + #32 + CInternalError + #32 + CPassword;
          6 : Result := AResult + #32 + CMissingArguments + #32 + CPassword;
        else
          Result := AResult + #32 + CUnknownError + #32 + CPassword;
        end;
      end;
    else
      Result := AResult + #32 + CUnknownError;
    end;
  end
  else
    Result := AResult + #32 + CUnknownError;
end;

function TMainWebModule.GetWindowsPath: String;
var
  LSize : Integer;
begin
  Result := '';

  LSize := GetWindowsDirectory(nil, 0);
  if (LSize > 0) then
  begin
    SetLength(Result, Succ(LSize));
    GetWindowsDirectory(@Result[1], Length(Result));

    Result := Trim(Result);
    if (Length(Result) > 0) then
    begin
      if (Result[Length(Result)] <> CPathDivider) then
        Result := Result + CPathDivider;
    end;
  end;
end;

procedure TMainWebModule.MainWebModuledefaultAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  LCGIDirectory : String;
  LParameters   : TStringList;
  LTextResult   : String;
  LValueRecord  : TValueRecord;
begin
  LCGIDirectory := GetCGIPath(Request.PathTranslated, Request.PathInfo, Request.ScriptName);
  if DirectoryExists(LCGIDirectory) then
  begin
    LValueRecord := ParseRequest(Request);

    case LValueRecord.Action of
      vaForward :
      begin
        if FileExists(LCGIDirectory + CForwardVBS) then
        begin
          LParameters := TStringList.Create;
          try
            LParameters.Add(CNoLogoParam);
            LParameters.Add(LCGIDirectory + CForwardVBS);
            if (Length(Trim(LValueRecord.Domain)) > 0) then
              LParameters.Add(LValueRecord.Domain);
            if (Length(Trim(LValueRecord.Username)) > 0) then
              LParameters.Add(LValueRecord.Username);
            if (Length(Trim(LValueRecord.Password)) > 0) then
              LParameters.Add(LValueRecord.Password);
            if (Length(Trim(LValueRecord.ForwardAddress)) > 0) then
              LParameters.Add(LValueRecord.ForwardAddress);

            LTextResult := Trim(GetApplicationOutput(GetWindowsPath + CCscriptExe, LParameters));
            Response.Content := GetResultString(LValueRecord.Action, LTextResult);
          finally
            LParameters.Free;
          end;
        end;
      end;

      vaPassword :
      begin
        if FileExists(LCGIDirectory + CPasswordVBS) then
        begin
          LParameters := TStringList.Create;
          try
            LParameters.Add(CNoLogoParam);
            LParameters.Add(LCGIDirectory + CPasswordVBS);
            if (Length(Trim(LValueRecord.Domain)) > 0) then
              LParameters.Add(LValueRecord.Domain);
            if (Length(Trim(LValueRecord.Username)) > 0) then
              LParameters.Add(LValueRecord.Username);
            if (Length(Trim(LValueRecord.Password)) > 0) then
              LParameters.Add(LValueRecord.Password);
            if (Length(Trim(LValueRecord.NewPassword)) > 0) then
              LParameters.Add(LValueRecord.NewPassword);

            LTextResult := Trim(GetApplicationOutput(GetWindowsPath + CCscriptExe, LParameters));
            Response.Content := GetResultString(LValueRecord.Action, LTextResult);
          finally
            LParameters.Free;
          end;
        end;
      end;
    else
      Response.Content := '';
    end;
  end;

  Handled := true;
end;

function TMainWebModule.ParseRequest(ARequest: TWebRequest) : TValueRecord;
var
  LAction     : String;
  LIndex      : Integer;
  LScriptName : String;
  LUsername   : String;
begin
  Result.Action         := vaUnknown;
  Result.Domain         := '';
  Result.Username       := '';
  Result.Password       := '';
  Result.ForwardAddress := '';
  Result.NewPassword    := '';

  if (ARequest <> nil) then
  begin
    LScriptName := AnsiLowerCase(Trim(ARequest.ScriptName));
    if (Length(LScriptName) > 0) then
    begin
      // kill trailing slash
      if (LScriptName[Length(LScriptName)] = CURLDivider) then
        Delete(LScriptName, Length(LScriptName), 1);

      // read trailing value - is username
      // kill trailing value
      for LIndex := Length(LScriptName) downto 1 do
      begin
        if (LScriptName[LIndex] = CURLDivider) then
        begin
          LUserName := Copy(LScriptName, Succ(LIndex), Length(LScriptName) - LIndex);
          Delete(LScriptName, LIndex, Length(LScriptName) - Pred(LIndex));

          Break;
        end;
      end;

      // read trailing value - is action
      // kill trailing value
      for LIndex := Length(LScriptName) downto 1 do
      begin
        if (LScriptName[LIndex] = CURLDivider) then
        begin
          LAction := Copy(LScriptName, Succ(LIndex), Length(LScriptName) - LIndex);
          Delete(LScriptName, LIndex, Length(LScriptName) - Pred(LIndex));

          Break;
        end;
      end;

      // check action string
      if AnsiSameText(LAction, CForwardAction) then
        Result.Action := vaForward;
      if AnsiSameText(LAction, CPasswordAction) then
        Result.Action := vaPassword;

      case Result.Action of
        vaForward :
        begin
          // read "forward" parameter
          LIndex := Request.QueryFields.IndexOfName(CForwardParam);
          if (LIndex >= 0) then
            Result.ForwardAddress := Request.QueryFields.ValueFromIndex[LIndex];

          // read "password" parameter
          LIndex := Request.QueryFields.IndexOfName(CPasswordParam);
          if (LIndex >= 0) then
            Result.Password := Request.QueryFields.ValueFromIndex[LIndex];

          Result.Domain   := Request.Host;
          Result.Username := LUserName;
        end;

        vaPassword :
        begin
          // read "new" parameter
          LIndex := Request.QueryFields.IndexOfName(CNewParam);
          if (LIndex >= 0) then
            Result.NewPassword := Request.QueryFields.ValueFromIndex[LIndex];

          // read "password" parameter
          LIndex := Request.QueryFields.IndexOfName(CPasswordParam);
          if (LIndex >= 0) then
            Result.Password := Request.QueryFields.ValueFromIndex[LIndex];

          Result.Domain   := Request.Host;
          Result.Username := LUserName;
        end;
      end;
    end;
  end;
end;

end.

In dem Programm selber gehen wir folgendermaßen vor:

  1. Wir parsen den URL-String.
  2. Wir führen das entsprechende VBScript aus.
  3. Wir lesen den Antwortwert aus stdout.
  4. Wir geben den erhaltenen Ergebniscode zurück.

Für den Zugriff habe ich mir ein tolles URL-Schema überlegt, das eingehalten werden muss, damit das Programm die richtigen Daten auslesen kann. Folgende Befehle gelten für das Setzen einer Mailumleitung:

1
2
https://[domain]/cgi-bin/[exedatei]/forward/[username]?password=[password]
https://[domain]/cgi-bin/[exedatei]/forward/[username]?password=[password]&forward=[email]

Durch das Setzen des forward-Parameters wird die Umleitung aktiviert. Durch Weglassen des Parameters wird die Umleitung deaktiviert. :-)

Für das Ändern des Passworts wird folgendes URL-Schema benutzt. Wenn man ein Mail-Forwarding einrichten kann, dann kann man auch sein Passwort ändern – die Befehle unterscheiden sich nur geringfügig:

1
https://[domain]/cgi-bin/[exedatei]/password]/[username]?password=[password]&new=[newpassword]

Was haltet ihr von dieser Form der Implementierung? Denkt ihr, ein Benutzer kann sich zwei URLs merke? Wie findet ihr den Lösungsansatz generell?

Update:
Der vorhandene Exploit wurde nun behoben. Das Problem war, dass die übergebenen Parameter nicht überprüft wurden, bevor sie in den auszuführenden Befehl eingebaut wurden. Nun werden Anführungszeichen escaped, um das Hinzufügen von zusätzlichen Parametern und andere Modifikationen des Befehls zu unterbinden (Stichwort Pipes).

Konfigurierende Grüße, Kenny




Natürlich wollen auch Schwangere im Winter warm verpackt und gegen Schnee und Kälte geschützt sein. Winterjacken, speziell hergestellt für Schwangere sind etwas ganz Besonderes und nicht leicht zu erwerben, da man auf die Frage, ob es Winterjacken für Schwangere gibt, häufig nur ein genervtes "Nein, haben wir nicht bekommt. Jetzt ist es wieder so weit Die neue Schwangerschaftsmode ist da! Wunderbar lang geschnitten, um den Bereich um Hüften und Po, sowie den Bauch vor Kälte zu schützen. Alle Modelle sind mit zahlreichen Taschen versehen, sodass Sie auch einige Accessoires für Sie und Ihr Baby einpacken können. Jedes Modell gibt es in mehreren Farben und auch in großen Größen.
Einige Winterjacken haben Kapuzen, die Sie vor jedem Wind schützen und durch ihren raffinierten Schnitt können einige Jacken sogar nach der Schwangerschaft getragen werden, ohne dass etwas auffällt. So kann die Jacke auch später noch verwendet werden und man muss für den nächsten Winter keine neue Jacke kaufen.



05 März 2010 ~ 14 Comments | ÄHNLICHE ARTIKEL

[Update] Unterminierung durch Feminist(inn)en

Eigentlich wollte ich mich mit dem Thema hier im Blog garnicht auseinander setzen, aber diese ganze Gekeife geht mir langsam sowas auf die Eier, dass ich nun meinen Senf dazu abgeben werde.

Erinnert sich noch jemand an die Zeit, in der alle Welt die Befürchtung hatte, die Piratenpartei würde durch die Rechten unterwandert werden? Nein, soweit ist es nicht gekommen. Dafür haben sie jetzt anscheinend geltungssüchtige Feministinnen an der Backe.

Angefangen hat das Debakel auf dem Landesparteitag in Berlin, auf dem Lena Simon die Piratinnen angekündigt hat – eine Gruppe innerhalb der Partei, die sich nur aus Frauen zusammensetzen soll und die ein Zufluchtsort für unterdrückte weibliche Piraten darstellen soll. Das ganze mit eigener, geschlossener Mailingliste versteht sich – der Feind männliche Pirat soll schließlich nicht wissen, wo überhaupt der Schuh drückt.

Statt einfach mal den Mund aufzumachen, wendet man sich stattdessen an die Presse, um seine 5 Minuten Ruhm zu ergattern. Muss eigentlich erwähnt werden, dass sich führende Frauen in der Partei – z.B. Heide Hagen (Beisitzerin des Berliner Landesvorstandes) – bereits gegen die Piratinnen ausgesprochen haben?

Aber um irgendwelche Probleme geht es wahrscheinlich garnicht: Zu diesem Schluss kann man kommen, wenn man sich mal mit Isi beschäftigt – eine augenscheinlich parteiferne Fürsprecherin. Allein der Profiltext spricht Bände: Frauen die gleichen Pflichten auferlegen wie den Männern? Böse! Männern soviele Rechte zustehen wie den Frauen (Männerhäuser, Männquote bei Lehrpositionen, etc.)? Ebenfalls böse! Ich nenne sowas Rosinenpickerei!
Wer sich mal in ihrem Blog umsieht, der wird sehr schnell sehen, woher der Wind weht: Es geht ums Prinzip! Basta! Auch das generische Maskulinum soll abgeschafft werden – weil, ja weil, es halt männlich ist. Pfui!

Ich jedenfalls unterstütze den Text Vielfalt statt Grabenkämpfe – der wurde übrigens von 5 Frauen verfasst. Ich sehe es nicht ein, dass sich ein Grüppchen gegen Diskriminierung ausspricht – diese jedoch nicht einmal belegen kann – und sich dann in ein abgeschottetes Refugium zurückzieht und damit alle anderen diskriminiert.

Sollte sich diese ganze Profilierung nicht bald wieder legen, dann mache ich meine Ankündigung wahr und gründe die Gayraten – damit endlich jedes männliche Parteimitglied anflirten kann, das ich will. Alles andere ist schließlich Diskriminierung aufgrund meiner sexuellen Identität! Jawohl ja!

Update:
Noch eine Ergänzung zu Isis Profiltext gemacht.

Unterminierte Grüße, Kenny

21 Februar 2010 ~ 0 Comments | ÄHNLICHE ARTIKEL

[Update] Benutzerpasswort des hMailServer ändern…

Eigentlich wollte ich ja Mercury/32 auf meinem Heimserver einsetzen, jedoch hat das Programm mich maßlos enttäuscht. Als Ersatz habe ich für den hMailServer entschieden, der stabil läuft und obendrein auch noch wesentlich einfacher zu konfigurieren ist.

Die Sache funktioniert sogar so gut, dass ich überlege, ob ich nicht weitere Domains auf meinen Heimserver umziehen soll. Bei diesen anderen Domains würden allerdings auch externe Benutzer mit dabei sein: Und genau die würden Probleme machen! :-(

Nein, nicht was ihr denkt :D ! Wer sich die E-Mail-Protokolle (IMAP, POP3, SMTP) schonmal angegeguckt hat, der wird eins feststellen können: Ein Benutzer kann nicht einfach sein Passwort ändern!
Bei den großen Webmail-Anbietern kann man das über deren Webseite machen – das ist ein Zusatzfeature und von Betreiber zu Betreiber unterschiedlich. Doch wie wird das bei mir möglich sein? Eine Lösung musste her! Und die sieht derzeit so aus:

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
  ' Wscript.Arguments(0) => domain name
 ' Wscript.Arguments(1) => username
 ' Wscript.Arguments(2) => old password
 ' Wscript.Arguments(3) => new password

  On Error Resume Next
  Err.Clear
 
  If Wscript.Arguments.Count = 4 Then
    Dim obApp
    Set obApp = CreateObject("hMailServer.Application")

    If Err.Number = 0 Then
      Call obApp.Authenticate(Wscript.Arguments(1) & "@" & Wscript.Arguments(0), Wscript.Arguments(2))
   
      If Err.Number = 0 Then
        Dim obDomain
        Set obDomain = obApp.Domains.ItemByName(Wscript.Arguments(0))
   
        If Err.Number = 0 Then
          Dim obAccount
          Set obAccount = obDomain.Accounts.ItemByAddress(Wscript.Arguments(1) & "@" & Wscript.Arguments(0))
   
          If Err.Number = 0 Then
            If obAccount.ValidatePassword(Wscript.Arguments(2)) Then
              obAccount.Password = Wscript.Arguments(3)  
              obAccount.Save

              WScript.StdOut.WriteLine "0" ' password set
           Else
              WScript.StdOut.WriteLine "1" ' old password is not correct
           End If
          Else
            WScript.StdOut.WriteLine "2" ' account does not exist
         End If
        Else
          WScript.StdOut.WriteLine "3" ' domain does not exist
       End If
      Else
        WScript.StdOut.WriteLine "4" ' old password is not correct
      End If
    Else
      WScript.StdOut.WriteLine "5" ' hMailServer.Application not available
   End If
  Else
    WScript.StdOut.WriteLine "6" ' wrong number of arguments
 End If

Hierbei handelt es sich um ein VBScript, das die COM-API benutzt, die der hMailServer bereitstellt. Dieses Script wird die Basis eines kleinen Servers werden, an dem man sich mit seiner E-Mail-Adresse und seinem Passwort anmelden und sein Passwort ändern können wird. Wie man das ganze mit SSL absichern kann, habe ich euch ja schon gezeigt. ;-)

Ja, für unerfahrene Benutzer könnte das Passwort ändern wirklich eine kleine Herausforderung werden – die geplante grafische Clientanwendung sollte die Hemmschwelle allerdings auf lange Sicht gesehen senken können. :-)

Update:
Mir ist gerade aufgefallen, dass ich eine wichtige Information vergessen habe! Und zwar muss das Script mit dem Windows Script Host cscript.exe aufgerufen werden. Ansonsten funktioniert die Ausgabe des Ergebniscodes nicht korrekt!

E-Mail-Grüße, Kenny

17 Februar 2010 ~ 5 Comments | ÄHNLICHE ARTIKEL

[Update] Köhler unterschreibt Internetzensurgesetz

Nachdem eigentlich alle aufgeatmet und der Ankündigung vertraut hatten, dass das Internsperrgesetz gestoppt werden würde, müssen nun wohl alle wieder in die Realität zurückgeholt werden: Horst Köhler hat das Netzsperrengesetz unterzeichnet.

Laut einer Erklärung hieß es

“Es bestanden keine durchgreifenden verfassungsrechtlichen Bedenken”

Ich salutiere ehrfürchtig vor der Inkompetenz der deutschen Politik!

Wer hat uns verraten?
Die Sozialdemokraten!
Wer hat uns verraten?
Die Freien Demokraten!
Wer hat uns verraten?
Die Christlich’ Demokraten!


Update:
Auch auf Heise wurde darüber berichtet. Wie nicht anders zu erwarten ist im dazugehörigen Forum eine rote Welle losgetreten worden.

Fassungslose Grüße, Kenny

12 Februar 2010 ~ 2 Comments | ÄHNLICHE ARTIKEL

[Update] MeaTLight: Nerven schonen an der Ampel

Autofahrer kennen es bestimmt – die Ampel schaltet nie so, wie es eigentlich sinnvoll wäre. Oft scheint es, als ob die Vorfahrtstraße länger grün hat, als die Seitenstraße – und das, obwohl die meisten Autos doch aus der Seitenstraße kommen. Vor allem im Berufsverkehr ist dieses unnötige Warten eine richtige Plage. Doch was kann man dagegen tun?

Genau über die Frage habe ich die letzten Tage nachgedacht und bin zu einer theoretischen Lösung gekommen: die MeaTLight (gesprochen “Meat Light”). Die Abkürzung steht für “Measuring Traffic Light” und macht auch genau das: Sie misst, wieviele Autos an der Ampel warten.

Sie misst? Sollte sie nicht lieber zählen?
Eigentlich schon, aber messen ist theoretisch einfacher als zählen. Um zählen zu können, muss man einzelne Fahrzeuge unterscheiden können – man muss die vorhandenen Gegebenheiten berücksichtigen, was einen Mehraufwand in der Entwicklung bedeutet. Zum messen kann man sich seinen eigenen Maßstab wählen. Man könnte z.B. eine Markierung auf der Fahrbahn anbringen, die Licht einer bestimmten Wellenlänge reflektiert. Wenn ein Auto auf der Fahrbahn steht, würde dieses die Markierung verdecken und ein etwaiger Sensor würde das erkennen können, da die das Licht nicht mehr kontrolliert reflektiert wird. Je nachdem, wie lang die Markierung ist, kann man messen, wie lang die wartende Autoschlange ist.

Der Rest ist dann relativ einfach: Während dem Umschalten misst die Ampel, wie viele Autos warten und berechnet daraus die Länge der Grünphase. Das kann problemlos im Wechsel geschehen, sodass die Fahrtrichtung, die im Moment wenig Verkehr verzeichnet auch weniger Zeit in Anspruch nimmt.

Jetzt mag der Einspruch kommen, dass doch längere Fahrzeuge (z.B. Busse und LKWs) eine längere Strecke verdecken und als mehrere Autos gewertet werden würden. Das mag in der Tat sein. Aber aus Erfahrung wissen wir alle, dass große Fahrzeuge auch entsprechend länger für das Anfahren benötigen, als kleine Fahrzeuge (es sei denn in dem kleinen Fahrzeug sitzt ein schlechter Autofahrer).

Nunja, die Idee ist natürlich nicht so ausgereift, wie zum Beispiel beim Projekt Light Traffic, aber ich wollte meine Idee einfach mal in die Welt hinaus posaunen. ;-)

Update:
Hihi! Kleine Notiz am Rande: Mein Artikel hier hat die Domain Meatlight.nl vom ersten Platz der Google-Suchergebnisse für “meatlight” verdrängt. Schon irgendwie lustig! :D

'meatlight' Suchergebnisse



Autofahrende Grüße, Kenny

12 Februar 2010 ~ 0 Comments | ÄHNLICHE ARTIKEL

[Update] Youtube mit neuem Design

Ich habe gerade mal wieder Youtube aufgerufen und wurde mit dem Hinweis begrüßt, dass ich dazu auserwählt wurde, die Betaversion des neuen Designs zu testen.

Youtube Design-Beta

Mein Resümee? Es ist hässlich und es ist unkomfortabel. Der obere Bereich ist nun ziemlich leer. Die Informationen zum Video befinden sich nun darunter – dadurch muss ich bei einer Auflösung von 1024×768 Pixeln scrollen. Zudem sind sie kaum noch zu erkennen, da sie im Design-Einheitsbrei untergehen.

Ich hoffe, dass noch massiv an dem Design gearbeitet wird, bevor es für alle Benutzer des Portals ausgerollt wird. Mit dem jetztigen Stand machen sie sich jedenfalls keine Freunde.

Hier findet man übrigens weitere Informationen zur Beta-Testphase.

Update:
Da einige Leute anscheinend keinen Zugriff auf die Beta haben, habe ich hier einen kleinen Screenshot des neuen Designs erstellt. Dann könnt ihr euch selber ein Bild machen.

Youtube Beta-Screenshot



Update:
Ich wollte noch ein paar positive Dinge zum neuen Design loswerden: Wenn man nach etwas gesucht hat, kriegt man nun eine Anzeige des nächsten Suchergebnisses (im Screenshot rechts oben). Wenn das abgespielte Video beendet ist, wird zudem auf das nächste Suchergebnis umgeschaltet. Ebenfalls gut finde ich die neue Statistikfunktion (im Screenshot unter dem Video). Ingesamt scheint man versucht zu haben, weniger Seitensprünge zu benötigen und mehr Content dynamisch nachzuladen.

Update:
Gerade herausgefunden: Wenn man ein Video abspielt und dann über die Suchleiste nach etwas anderem sucht, werden die Suchergebnisse angezeigt und nebenbei läuft das gerade gespielte Video (im Kleinformat) unterbrechungsfrei weiter! :D

Enttäuschte Grüße, Kenny

31 Januar 2010 ~ 5 Comments | ÄHNLICHE ARTIKEL

[Update] 3D für den Heim-PC

Nachdem ich am Freitag eine Idee für ein neues Projekt hatte – von dem ich natürlich noch berichten werde – bin ich zu Saturn am Alexanderplatz gefahren, um mir USB-NumPads zu besorgen. Ich hatte zuerst bei MediaMarkt im Kaufpark Eiche danach gesucht: Dort gab es allerdings nur Bluetooth NumPads von Microsoft – das Stück für 40€ :-( ! Bei Saturn habe ich von SpeedLink einfache NumPads für 15€ das Stück bekommen… plus einen Blick in die Zukunft! :D

nVidia 3D-Brille

An einem Stand konnte man die neue 3D-Brille von nVidia ausprobieren; als Testobjekte dienten Screenshots von Game-Größen wie Lara Croft!
Und in der Tat: Der 3D-Effekt ist atemberaubend! Man sieht z.B. ein umstürzendes Auto, bei dem man denkt, man könne es wieder zurechtrücken. Bei einer Kampfszene erkennt man, welcher Kämpfer welche Position im Raum einnimmt. Und das ganze natürlich gestochen scharf!

Man wird wirklich dazu verleitet, den Kopf zur Seite zu bewegen, weil man denkt, dass man dadurch vllt. in die Ecke des Raums gucken könnte. Stattdessen verzerrt sich jedoch die Anzeige – ein direkter Blick auf den Monitor ist also empfehlenswert.

200€ für die Brille (plus evtl. eine kompatible Grafikkarte) und nochmal ein wenig für ein 3D-Spiel wird sich wohl nicht jeder sofort leisten können oder wollen, aber ich denke, dass die Technik nun reif ist, den Consumermarkt zu erobern. Die Brille von nVidia machte auf mich jedenfalls einen sehr soliden Eindruck.

Zum Einsatz kam bei der Demo ein handelsüblicher Monitor. Es bleibt deshalb abzuwarten, ob sich solche generellen Lösungen nicht vielleicht auch gegen die kommende Generation von “3D-Fernsehern” durchsetzen können.

Update:
Ich habe gerade mal ein wenig gegooglet und bin dabei auf einen Artikel von Heise gestoßen. In diesem heißt es, dass für die Brille ein Monitor mit 120Hz-Technik benötigt wird, sodass jedes Auge mit 60Hz aufgelöst werden kann. Zudem heißt es in dem Artikel, dass der 3D-Effekt bei vielen bereits erhältlichen Spielen funktioniert. Na das denn ich doch mal genial! Dann fehlt ja nur noch eine neuere nVidia-Grafikkarte der 8er oder 9er Modellserie! :D

3D-Grüße, Kenny

26 Januar 2010 ~ 9 Comments | ÄHNLICHE ARTIKEL

[Update] Naziaufmärsche und Parteigezanke

Eigentlich hatte ich mir ja vorgenommen, zu dem Thema meine Klappe zu halten, aber inzwischen gibt es so viele Meinungen dazu im Netz, dass ich auch meine mal kundtun möchte. Thema ist die Initiative “Dresden Nazifrei”, die dazu aufruft, Europas größten Naziaufmarsch, der am 13.02.2010 in Dresden stattfinden soll, mit einer Sitzblockade zu vereiteln.

Dieser Aufruf ist in den letzten Tagen in die Schlagzeilen geraten, nachdem Razzien durchgeführt, Werbematerial beschlagnahmt und Plakatierer festgenommen wurden. Parallel dazu wurde die Webseite der Initiative Dresden-Nazifrei.de vom LKA Sachsen gesperrt, obwohl dieses Vorgehen von Juristen als unhaltbar angesehen wird (die Webseite ist inzwischen übrigens unter Dresden-Nazifrei.com erreichbar).

Ein ganz anderes Feuer brodelte – und brodelt immernoch – innerhalb der Piratenpartei. Dort ist man zwiegespalten über die Teilnahme an dieser Blockade. Die einen berufen sich auf § 1 Abs. 1 der Bundessatzung, der wie folgt lautet:

(1) Die Piratenpartei Deutschland (PIRATEN) ist eine Partei im Sinne des Grundgesetzes der Bundesrepublik Deutschland und des Parteiengesetzes. Sie vereinigt Piraten ohne Unterschied der Staatsangehörigkeit, des Standes, der Herkunft, der ethnischen Zugehörigkeit, des Geschlechts, der sexuellen Orientierung und des Bekenntnisses, die beim Aufbau und Ausbau eines demokratischen Rechtsstaates und einer modernen freiheitlichen Gesellschaftsordnung geprägt vom Geiste sozialer Gerechtigkeit mitwirken wollen. Totalitäre, diktatorische und faschistische Bestrebungen jeder Art lehnt die Piratenpartei Deutschland entschieden ab.
(Bundessatzung der Piratenpartei Deutschland, Hervorhebung durch mich)

So lehnt Sven Scholz zum Beispiel jegliche Meinungsfreiheit für Nazis ab es ab, dass die Ideologie der Nazis unter dem Deckmantel der Meinungsfreiheit geschützt wird, da er die Nazi-Ideologie nicht als Meinung sondern als Verbrechen ansieht:

Zur “Meinungsfreiheit” der Nazis: Ich sehe eine Ideologie, die Menschenrechte nicht nur missachtet sondern ihnen offen widerspricht nicht als “Meinung”, die durch Menschenrechte gedeckt ist. Naziideologie ist keine Meinung sondern ein Verbrechen.
(Artikel in Sven Scholz’ Blog)

Die andere Seite widerum beruft sich ausschließlich auf § 5 Abs. 1 des Grundgesetzes, in dem es heißt:

(1) Jeder hat das Recht, seine Meinung in Wort, Schrift und Bild frei zu äußern und zu verbreiten und sich aus allgemein zugänglichen Quellen ungehindert zu unterrichten. Die Pressefreiheit und die Freiheit der Berichterstattung durch Rundfunk und Film werden gewährleistet. Eine Zensur findet nicht statt.
(§ 5 Abs. 1 GG)

Natürlich ist es edel, sich nur auf diesen Absatz zu stürzen, allerdings geht der § 5 noch weiter. Auch dieser sollte unbedingt Beachtung finden, bevor man für Menschenverächter in die Bresche springt:

(2) Diese Rechte finden ihre Schranken in den Vorschriften der allgemeinen Gesetze, den gesetzlichen Bestimmungen zum Schutze der Jugend und in dem Recht der persönlichen Ehre.
(§ 5 Abs. 2 GG)

In meinen Augen ist es nicht hinnehmbar, dass eine Gruppe die Rechte, die ihnen zustehen, missbrauchen, um damit die Rechte anderer Gruppen öffentlich zu unterminieren. In diesen Fällen muss der demokratische Staat – zu dem sich auch die Piratenpartei bekennt – aktiv werden und die Rechte und die Ehre der einzelnen Bürger schützen, die bei solchen Naziaufmärchen tangiert werden.

Das wird wahrscheinlich auch der Grund sein, weshalb der Landesverband Sachsen im Piratenpartei-Wiki seine Unterstützung bei der Teilname an “öffentlichen, friedlichen Aktionen und Demonstrationen” erklärt hat. Schön war auch zu sehen, dass der Bundesverband dies auch kurze Zeit später auf der offiziellen Webseite der Piratenpartei Deutschland nachgeholt hat. Man darf jedoch nicht vergessen, dass angemeldete Demonstrationen und Prosteste den besseren Weg zur friedlichen Bekämpfung von Verfassungsfeinden darstellen.
Genau diese Aussage bekräftigt auch noch einmal die Pressesprecherin des LV Berlin – Lena Rohrbach – in einem Kommentar im Spreeblick-Blog. Aktionen gegen Naziaufmärsche sind gerechtfertigt, solange probate, verfassungskonforme Mittel dafür eingesetzt werden.

Und für alle Gegner solcher Gegendemonstrationen, die ausschließlich auf den § 5 Abs 1. GG pochen, möchte ich abschließend gerne noch den Kommentar von Julian anführen, der das ganze in meinen Augen wunderbar zusammenfasst:

Jeder hat das recht zu demonstrieren, auch die Gegner einer anderen Demo. Meinungsfreiheit heisst nicht, seine Meinung unwidersprochen kundtun zu dürfen.
(Kommentar von “Julian” auf SvenScholz.de)

Diese Aussage trifft haargenau meinen Gedanken: Natürlich dürfen die Leute ihre Gedanken äußern, jedoch müssen sie damit rechnen, dass sie vom Staat dazu ermahnt werden, nicht die Rechte und die Ehre anderer zu verletzen und dass sich ihn andere Leute in den Weg stellen, die ihre Meinung nicht teilen und als Gegensprecher auftreten. So ist das nunmal in einer Demokratie: Es gibt immer mehr als nur eine Meinung. ;-)

Update:
Im Zuge eines Kommentars von Sven Scholz habe ich den Absatz über seine Ansichten zur Meinungsfreiheit der Nazis abgeändert. Danke für die Korrektur! :D

Demokratische Grüße, Kenny

22 Januar 2010 ~ 5 Comments | ÄHNLICHE ARTIKEL

[Update] Google und Twitter

Gerade habe ich bei Google mal wieder nach mir selbst gesucht, um zu gucken, was man denn so alles findet. Und ob man es glaubt oder nicht: Google hat jetzt eine integrierte Twitter-Suche. Sie haben ja schon früher einzelne Tweets in den Ergebnissen mit angezeigt, aber diese werden jetzt sogar schon in einer eigenen Box angezeigt, die sich automatisch aktualisiert!

Google Twitter-Box

Wer die pure Twitter-Ansicht haben will, kann das übrigens über diesen Link erreichen. Na dann viel Spaß damit! Ich persönlich sehe das ganze eher mit Argwohn, denn jetzt ist es vorbei mit “Ach, ist doch bloß Twitter!”.

Update:
Nach ein bisschen weiterem Testen komme ich zu dem Ergebnis, dass Google dringend noch nachbessern muss. So aktuell, wie Google behauptet, sind die angezeigten Tweets nicht immer. Teilweise werden ältere Tweets angezeigt – manchmal werden die neuen dann schnell nachgeladen, manchmal aber auch nicht.

Twitternde Grüße, Kenny

20 Januar 2010 ~ 2 Comments | ÄHNLICHE ARTIKEL

[Update] RunAs für normale Dokumente anwenden

Hannes hat letztens das Tool CPAU vorgestellt, das im Grunde genauso funktioniert, wie das Windows-interne runas-Programm. Wer dessen Funktionalität nicht kennt: Es ist dazu da, um eine Anwendung mit den Rechten eines anderen Benutzers ausführen zu können.

Nun ist bei ihm das Problem aufgetreten, dass es ihm nicht möglich ist, MSP-Dateien auszuführen. Grund hierfür ist, dass es sich bei MSP-Dateien nicht um echte, ausführbare Dateien handelt, sondern um Dokumente – also im Grunde wie Bilddateien.

Wenn ihr sehen wollt, was Windows im Hintergrund macht, wenn ihr ein Dokument doppelt anklickt, könnt ihr folgendes machen:

  1. Drückt die Tastenkombination Windowstaste+R. Es öffnet sich das Ausführen-Fenster.
  2. Gebt in dem Fenster “regedit” ein und drückt Enter. Es öffnet sich der Registry-Editor.

    Ausführen-Dialog

  3. Öffnet unter “Arbeitsplatz” den Baum “HKEY_CLASSES_ROOT”. Darunter findet ihr eine Liste aller Dateiendungen.

    HKEY_CLASSES_ROOT

  4. Öffnet nun den Eintrag einer Dateiendung – zum Beispiel “.jpg”. Ihr seht ein paar Unterelemente.

    .jpg Knoten

  5. Guckt, ob es den Unterbaum “shell/open/command” gibt. Falls ja, macht weiter mit Punkt 8, falls nein, macht weiter mit Punkt 6.
  6. Klickt den aktuellen Baumeintrag (z.B. “.jpg”) an, dieser sollte einen Wert “(Standard)” beinhalten. Der darin gespeicherte Wert ist ein Platzhalter.

    .jpg-(Standard)-Wert

  7. Sucht einen Baumeintrag, der den Namen des Platzhalters entspricht. Die Platzhalter dienen dazu, dass mehrere Dateiendungen sich genau gleich verhalten (z.B. “.jpg” und “.jpeg”).

    jpegfile Knoten

  8. Öffnet nun den Unterbaum “shell/open/command”. Dieser Knoten bestimmt, was geschehen soll, wenn eine Datei dieses Typs geöffnet werden soll.

    shell/open/command Knoten

  9. Seht euch nun den Wert “(Standard)” an. Dieser beinhaltet den tatsächlich ausgeführten Befehl zu einer Dateiendung (z.B. bei einem Doppelklick). Der Parameter “%1″ wird bei der Ausführung mit dem entsprechenden Dateinamen ersetzt. Einige Dateitypen (z.B. MSI-Dateien) können zusätzliche Parameter erhalten. Diese können mit dem Parameter “%*” übergeben werden.

    shell/open/command-(Standard)-Wert

(Für diejenigen unter euch, die gerne experimentieren: Lasst die Finger von dem Knoten “exefile”! Wenn ihr diesen unbedarft ändert, zerschießt ihr euch das ganze System. Um das dann wieder gerade zu biegen, müsst ihr remote den entsprechenden Registry-Hive mounten und den Registry-Eintrag reparieren.)

Nach diesem kleinen Exkurs kommen wir nun zurück zum Thema: Das Problem, weshalb die runas-Programme diese MSP-Datei nicht öffnen können, liegt wahrscheinlich daran, dass sie versuchen, die Datei direkt auszuführen – dabei müssten sie doch erst nachgucken, mit welchem Programm die Datei geöffnet werden muss! Und genau hierfür habe ich ein kleines Programm mit dem Namen “execute” geschrieben: Es macht nicht viel, sondern öffnet eine angegebene Datei einfach anhand des Befehls, der dort in der Registry hinterlegt ist. Dabei ist es egal, ob es sich um ein Programm, ein Bild oder etwas anderes handelt. Den Quelltext des Programms findet ihr hier:

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
program execute;

uses
  Windows,
  SysUtils,
  ShellAPI,
  ActiveX;

var
  VCOMCode    : HRESULT;
  VIndex      : Integer;
  VParameters : String;
  VReturnCode : Cardinal;

begin
  ExitCode := 0; // application terminated successfully

  if (ParamCount > 0) then
  begin
    VParameters := '';
    for VIndex := 2 to ParamCount do
      VParameters := VParameters + '"' + ParamStr(VIndex) + '" ';
    Delete(VParameters, Length(VParameters), 1); // trim last space character

    VCOMCode := CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE);
    if ((VCOMCode = S_OK) or (VCOMCode = S_FALSE)) then
    begin
      try
        VReturnCode := ShellExecute(0,                                       // hwnd,
                                    'open',                                  // lpOperation,
                                    PAnsiChar(ParamStr(1)),                  // lpFile,
                                    PAnsiChar(VParameters),                  // lpParameters,
                                    PAnsiChar(ExtractFilePath(ParamStr(1))), // lpDirectory,
                                    SW_SHOWNORMAL                            // nShowCmd
                                   );

        if (VReturnCode <= 32) then
          ExitCode := 100 + VReturnCode; // file could not be executed
      finally
        CoUninitialize();
      end;
    end
    else
      ExitCode := 2; // COM could not be initialized
  end
  else
    ExitCode := 1; // file was not provided
end.

Die Verwendung der Anwendung ist super einfach: Ihr ruft das Programm einfach mit dem Pfad der auszuführenden Datei als ersten Parameter auf – alle weiteren Parameter werden an die Datei als weitere Parameter übergeben.

In diesem Beispiel wird z.B. die Kommandozeile mit den Rechten des Administrators aufgerufen, Google angepingt und die Kommandozeile danach offen gehalten:

1
runas /user:Administrator "execute cmd /K ping \"google.de\""

Bitte beachtet, dass der gesamte Aufruf mit allen Parametern für das aufgerufene Dokument in einem Parameter an runas übergeben werden muss! Sollte es nötig sein, Anführungungszeichen für die eigentlichen Parameter zu benutzen, so müssen diese mit einem Backslash “escaped” werden. Seht euch den Parameter \”google.de\” als Beispiel an. ;-)

Damit sich jetzt nicht jeder einen Pascal-Compiler herunterladen muss, habe ich hier das Programm bereits für euch kompiliert:

  Execute (22.9 KiB, 85 hits)

Ich hoffe, euch hat dieser kleine Ausflug in die Welt der Dateitypen gefallen und ihr habt ein bisschen was darüber gelernt, wie Windows eure Dateien intern behandelt. :-)

Zum Schluss noch etwas Rechtliches:
Der Autor dieses Programms haftet nicht für Schäden an Soft- oder Hardware oder Vermögensschäden, die durch das Benutzen des Programms entstehen, es sei denn, diese beruhen auf einem grob fahrlässigen oder vorsätzlichen Handeln des Autors, seiner Erfüllungsgehilfen oder seiner gesetzlichen Vertreter.
Für Schäden an der Gesundheit, dem Körper oder dem Leben des Nutzers haftet der Autor uneingeschränkt.


Update:
Ich sorge nun vor dem Aufrufen noch dafür, dass COM ordentlich initialisiert und danach auch wieder deinitialisiert wird. Man weiß ja nie. ;-)

Aufrufende Grüße, Kenny

P.S.: Wie zu erkennen ist, verwende ich einfach die API-Funktion ShellExecute(). Wer Langeweile hat und sich mit dem Parsen der Befehle herumärgern will, der kann das ganze natürlich auch nach dem oben beschriebenen Schema nachbauen (Action auslesen und über CreateProcess() nachbilden).

145
no-www.org extra-www.org

Datenbank: 45 Abfragen in 0.7460.746 Sekunden